[
  {
    "path": ".editorconfig",
    "content": "[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\nmax_line_length = 120\ntab_width = 4\ntrim_trailing_whitespace = false\nij_continuation_indent_size = 8\nij_formatter_off_tag = @formatter:off\nij_formatter_on_tag = @formatter:on\nij_formatter_tags_enabled = true\nij_smart_tabs = false\nij_visual_guides = none\nij_wrap_on_typing = false\n\n[*.blade.php]\nij_continuation_indent_size = 4\nij_blade_keep_indents_on_empty_lines = false\n\n[*.css]\nij_css_align_closing_brace_with_properties = false\nij_css_blank_lines_around_nested_selector = 1\nij_css_blank_lines_between_blocks = 1\nij_css_block_comment_add_space = true\nij_css_brace_placement = end_of_line\nij_css_enforce_quotes_on_format = true\nij_css_hex_color_long_format = true\nij_css_hex_color_lower_case = false\nij_css_hex_color_short_format = false\nij_css_hex_color_upper_case = true\nij_css_keep_blank_lines_in_code = 1\nij_css_keep_indents_on_empty_lines = false\nij_css_keep_single_line_blocks = false\nij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow\nij_css_space_after_colon = true\nij_css_space_before_opening_brace = true\nij_css_use_double_quotes = true\nij_css_value_alignment = do_not_align\n\n[*.less]\nij_less_align_closing_brace_with_properties = false\nij_less_blank_lines_around_nested_selector = 1\nij_less_blank_lines_between_blocks = 1\nij_less_block_comment_add_space = false\nij_less_brace_placement = 0\nij_less_enforce_quotes_on_format = false\nij_less_hex_color_long_format = true\nij_less_hex_color_lower_case = false\nij_less_hex_color_short_format = false\nij_less_hex_color_upper_case = true\nij_less_keep_blank_lines_in_code = 2\nij_less_keep_indents_on_empty_lines = false\nij_less_keep_single_line_blocks = false\nij_less_line_comment_add_space = false\nij_less_line_comment_at_first_column = false\nij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow\nij_less_space_after_colon = true\nij_less_space_before_opening_brace = true\nij_less_use_double_quotes = true\nij_less_value_alignment = 0\n\n[*.sass]\nij_sass_align_closing_brace_with_properties = false\nij_sass_blank_lines_around_nested_selector = 1\nij_sass_blank_lines_between_blocks = 1\nij_sass_brace_placement = 0\nij_sass_enforce_quotes_on_format = false\nij_sass_hex_color_long_format = false\nij_sass_hex_color_lower_case = false\nij_sass_hex_color_short_format = false\nij_sass_hex_color_upper_case = false\nij_sass_keep_blank_lines_in_code = 2\nij_sass_keep_indents_on_empty_lines = false\nij_sass_keep_single_line_blocks = false\nij_sass_line_comment_add_space = false\nij_sass_line_comment_at_first_column = false\nij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow\nij_sass_space_after_colon = true\nij_sass_space_before_opening_brace = true\nij_sass_use_double_quotes = true\nij_sass_value_alignment = 0\n\n[*.scss]\nij_scss_align_closing_brace_with_properties = false\nij_scss_blank_lines_around_nested_selector = 1\nij_scss_blank_lines_between_blocks = 1\nij_scss_block_comment_add_space = true\nij_scss_brace_placement = 0\nij_scss_enforce_quotes_on_format = true\nij_scss_hex_color_long_format = true\nij_scss_hex_color_lower_case = false\nij_scss_hex_color_short_format = false\nij_scss_hex_color_upper_case = true\nij_scss_keep_blank_lines_in_code = 1\nij_scss_keep_indents_on_empty_lines = false\nij_scss_keep_single_line_blocks = false\nij_scss_line_comment_add_space = false\nij_scss_line_comment_at_first_column = false\nij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow\nij_scss_space_after_colon = true\nij_scss_space_before_opening_brace = true\nij_scss_use_double_quotes = true\nij_scss_value_alignment = 0\n\n[*.twig]\nij_twig_keep_indents_on_empty_lines = false\nij_twig_spaces_inside_comments_delimiters = true\nij_twig_spaces_inside_delimiters = true\nij_twig_spaces_inside_variable_delimiters = true\n\n[*.vue]\nij_continuation_indent_size = 4\nij_vue_indent_children_of_top_level = template\nij_vue_interpolation_new_line_after_start_delimiter = true\nij_vue_interpolation_new_line_before_end_delimiter = true\nij_vue_interpolation_wrap = off\nij_vue_keep_indents_on_empty_lines = false\nij_vue_spaces_within_interpolation_expressions = true\n\n[.editorconfig]\nij_editorconfig_align_group_field_declarations = false\nij_editorconfig_space_after_colon = false\nij_editorconfig_space_after_comma = true\nij_editorconfig_space_before_colon = false\nij_editorconfig_space_before_comma = false\nij_editorconfig_spaces_around_assignment_operators = true\n\n[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}]\nij_xml_align_attributes = true\nij_xml_align_text = false\nij_xml_attribute_wrap = normal\nij_xml_block_comment_add_space = true\nij_xml_block_comment_at_first_column = true\nij_xml_keep_blank_lines = 2\nij_xml_keep_indents_on_empty_lines = false\nij_xml_keep_line_breaks = true\nij_xml_keep_line_breaks_in_text = true\nij_xml_keep_whitespaces = false\nij_xml_keep_whitespaces_around_cdata = preserve\nij_xml_keep_whitespaces_inside_cdata = false\nij_xml_line_comment_at_first_column = true\nij_xml_space_after_tag_name = false\nij_xml_space_around_equals_in_attribute = false\nij_xml_space_inside_empty_tag = true\nij_xml_text_wrap = normal\n\n[{*.ats,*.cts,*.mts,*.ts}]\nij_continuation_indent_size = 4\nij_typescript_align_imports = false\nij_typescript_align_multiline_array_initializer_expression = false\nij_typescript_align_multiline_binary_operation = false\nij_typescript_align_multiline_chained_methods = false\nij_typescript_align_multiline_extends_list = false\nij_typescript_align_multiline_for = true\nij_typescript_align_multiline_parameters = true\nij_typescript_align_multiline_parameters_in_calls = false\nij_typescript_align_multiline_ternary_operation = false\nij_typescript_align_object_properties = 0\nij_typescript_align_union_types = false\nij_typescript_align_var_statements = 0\nij_typescript_array_initializer_new_line_after_left_brace = false\nij_typescript_array_initializer_right_brace_on_new_line = false\nij_typescript_array_initializer_wrap = off\nij_typescript_assignment_wrap = off\nij_typescript_binary_operation_sign_on_next_line = false\nij_typescript_binary_operation_wrap = off\nij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**\nij_typescript_blank_lines_after_imports = 1\nij_typescript_blank_lines_around_class = 1\nij_typescript_blank_lines_around_field = 0\nij_typescript_blank_lines_around_field_in_interface = 0\nij_typescript_blank_lines_around_function = 1\nij_typescript_blank_lines_around_method = 1\nij_typescript_blank_lines_around_method_in_interface = 1\nij_typescript_block_brace_style = end_of_line\nij_typescript_block_comment_add_space = false\nij_typescript_block_comment_at_first_column = true\nij_typescript_call_parameters_new_line_after_left_paren = false\nij_typescript_call_parameters_right_paren_on_new_line = false\nij_typescript_call_parameters_wrap = off\nij_typescript_catch_on_new_line = false\nij_typescript_chained_call_dot_on_new_line = true\nij_typescript_class_brace_style = next_line\nij_typescript_comma_on_new_line = false\nij_typescript_do_while_brace_force = never\nij_typescript_else_on_new_line = false\nij_typescript_enforce_trailing_comma = remove\nij_typescript_enum_constants_wrap = on_every_item\nij_typescript_extends_keyword_wrap = off\nij_typescript_extends_list_wrap = off\nij_typescript_field_prefix = _\nij_typescript_file_name_style = relaxed\nij_typescript_finally_on_new_line = false\nij_typescript_for_brace_force = never\nij_typescript_for_statement_new_line_after_left_paren = false\nij_typescript_for_statement_right_paren_on_new_line = false\nij_typescript_for_statement_wrap = off\nij_typescript_force_quote_style = true\nij_typescript_force_semicolon_style = true\nij_typescript_function_expression_brace_style = end_of_line\nij_typescript_if_brace_force = never\nij_typescript_import_merge_members = global\nij_typescript_import_prefer_absolute_path = global\nij_typescript_import_sort_members = true\nij_typescript_import_sort_module_name = false\nij_typescript_import_use_node_resolution = true\nij_typescript_imports_wrap = on_every_item\nij_typescript_indent_case_from_switch = true\nij_typescript_indent_chained_calls = true\nij_typescript_indent_package_children = 0\nij_typescript_jsdoc_include_types = false\nij_typescript_jsx_attribute_value = braces\nij_typescript_keep_blank_lines_in_code = 1\nij_typescript_keep_first_column_comment = true\nij_typescript_keep_indents_on_empty_lines = false\nij_typescript_keep_line_breaks = true\nij_typescript_keep_simple_blocks_in_one_line = false\nij_typescript_keep_simple_methods_in_one_line = false\nij_typescript_line_comment_add_space = true\nij_typescript_line_comment_at_first_column = false\nij_typescript_method_brace_style = next_line\nij_typescript_method_call_chain_wrap = off\nij_typescript_method_parameters_new_line_after_left_paren = false\nij_typescript_method_parameters_right_paren_on_new_line = false\nij_typescript_method_parameters_wrap = off\nij_typescript_object_literal_wrap = on_every_item\nij_typescript_object_types_wrap = on_every_item\nij_typescript_parentheses_expression_new_line_after_left_paren = false\nij_typescript_parentheses_expression_right_paren_on_new_line = false\nij_typescript_place_assignment_sign_on_next_line = false\nij_typescript_prefer_as_type_cast = false\nij_typescript_prefer_explicit_types_function_expression_returns = false\nij_typescript_prefer_explicit_types_function_returns = false\nij_typescript_prefer_explicit_types_vars_fields = false\nij_typescript_prefer_parameters_wrap = false\nij_typescript_reformat_c_style_comments = false\nij_typescript_space_after_colon = true\nij_typescript_space_after_comma = true\nij_typescript_space_after_dots_in_rest_parameter = false\nij_typescript_space_after_generator_mult = true\nij_typescript_space_after_property_colon = true\nij_typescript_space_after_quest = true\nij_typescript_space_after_type_colon = true\nij_typescript_space_after_unary_not = true\nij_typescript_space_before_async_arrow_lparen = true\nij_typescript_space_before_catch_keyword = true\nij_typescript_space_before_catch_left_brace = true\nij_typescript_space_before_catch_parentheses = true\nij_typescript_space_before_class_lbrace = true\nij_typescript_space_before_class_left_brace = true\nij_typescript_space_before_colon = true\nij_typescript_space_before_comma = false\nij_typescript_space_before_do_left_brace = true\nij_typescript_space_before_else_keyword = true\nij_typescript_space_before_else_left_brace = true\nij_typescript_space_before_finally_keyword = true\nij_typescript_space_before_finally_left_brace = true\nij_typescript_space_before_for_left_brace = true\nij_typescript_space_before_for_parentheses = true\nij_typescript_space_before_for_semicolon = false\nij_typescript_space_before_function_left_parenth = true\nij_typescript_space_before_generator_mult = false\nij_typescript_space_before_if_left_brace = true\nij_typescript_space_before_if_parentheses = true\nij_typescript_space_before_method_call_parentheses = false\nij_typescript_space_before_method_left_brace = true\nij_typescript_space_before_method_parentheses = false\nij_typescript_space_before_property_colon = false\nij_typescript_space_before_quest = true\nij_typescript_space_before_switch_left_brace = true\nij_typescript_space_before_switch_parentheses = true\nij_typescript_space_before_try_left_brace = true\nij_typescript_space_before_type_colon = false\nij_typescript_space_before_unary_not = false\nij_typescript_space_before_while_keyword = true\nij_typescript_space_before_while_left_brace = true\nij_typescript_space_before_while_parentheses = true\nij_typescript_spaces_around_additive_operators = true\nij_typescript_spaces_around_arrow_function_operator = true\nij_typescript_spaces_around_assignment_operators = true\nij_typescript_spaces_around_bitwise_operators = true\nij_typescript_spaces_around_equality_operators = true\nij_typescript_spaces_around_logical_operators = true\nij_typescript_spaces_around_multiplicative_operators = true\nij_typescript_spaces_around_relational_operators = true\nij_typescript_spaces_around_shift_operators = true\nij_typescript_spaces_around_unary_operator = false\nij_typescript_spaces_within_array_initializer_brackets = false\nij_typescript_spaces_within_brackets = false\nij_typescript_spaces_within_catch_parentheses = false\nij_typescript_spaces_within_for_parentheses = false\nij_typescript_spaces_within_if_parentheses = false\nij_typescript_spaces_within_imports = true\nij_typescript_spaces_within_interpolation_expressions = true\nij_typescript_spaces_within_method_call_parentheses = false\nij_typescript_spaces_within_method_parentheses = false\nij_typescript_spaces_within_object_literal_braces = true\nij_typescript_spaces_within_object_type_braces = true\nij_typescript_spaces_within_parentheses = false\nij_typescript_spaces_within_switch_parentheses = false\nij_typescript_spaces_within_type_assertion = false\nij_typescript_spaces_within_union_types = true\nij_typescript_spaces_within_while_parentheses = false\nij_typescript_special_else_if_treatment = true\nij_typescript_ternary_operation_signs_on_next_line = false\nij_typescript_ternary_operation_wrap = off\nij_typescript_union_types_wrap = on_every_item\nij_typescript_use_chained_calls_group_indents = false\nij_typescript_use_double_quotes = false\nij_typescript_use_explicit_js_extension = auto\nij_typescript_use_path_mapping = always\nij_typescript_use_public_modifier = false\nij_typescript_use_semicolon_after_statement = false\nij_typescript_var_declaration_wrap = normal\nij_typescript_while_brace_force = never\nij_typescript_while_on_new_line = false\nij_typescript_wrap_comments = false\n\n[{*.bash,*.sh,*.zsh}]\nij_shell_binary_ops_start_line = false\nij_shell_keep_column_alignment_padding = false\nij_shell_minify_program = false\nij_shell_redirect_followed_by_space = false\nij_shell_switch_cases_indented = false\nij_shell_use_unix_line_separator = true\n\n[{*.cjs,*.js}]\nij_continuation_indent_size = 4\nij_javascript_align_imports = false\nij_javascript_align_multiline_array_initializer_expression = false\nij_javascript_align_multiline_binary_operation = false\nij_javascript_align_multiline_chained_methods = false\nij_javascript_align_multiline_extends_list = false\nij_javascript_align_multiline_for = true\nij_javascript_align_multiline_parameters = true\nij_javascript_align_multiline_parameters_in_calls = false\nij_javascript_align_multiline_ternary_operation = false\nij_javascript_align_object_properties = 0\nij_javascript_align_union_types = false\nij_javascript_align_var_statements = 1\nij_javascript_array_initializer_new_line_after_left_brace = true\nij_javascript_array_initializer_right_brace_on_new_line = true\nij_javascript_array_initializer_wrap = on_every_item\nij_javascript_assignment_wrap = off\nij_javascript_binary_operation_sign_on_next_line = false\nij_javascript_binary_operation_wrap = off\nij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**\nij_javascript_blank_lines_after_imports = 1\nij_javascript_blank_lines_around_class = 1\nij_javascript_blank_lines_around_field = 0\nij_javascript_blank_lines_around_function = 1\nij_javascript_blank_lines_around_method = 1\nij_javascript_block_brace_style = end_of_line\nij_javascript_block_comment_add_space = false\nij_javascript_block_comment_at_first_column = true\nij_javascript_call_parameters_new_line_after_left_paren = false\nij_javascript_call_parameters_right_paren_on_new_line = false\nij_javascript_call_parameters_wrap = off\nij_javascript_catch_on_new_line = false\nij_javascript_chained_call_dot_on_new_line = true\nij_javascript_class_brace_style = next_line\nij_javascript_comma_on_new_line = false\nij_javascript_do_while_brace_force = never\nij_javascript_else_on_new_line = false\nij_javascript_enforce_trailing_comma = remove\nij_javascript_extends_keyword_wrap = off\nij_javascript_extends_list_wrap = off\nij_javascript_field_prefix = _\nij_javascript_file_name_style = lisp_case\nij_javascript_finally_on_new_line = false\nij_javascript_for_brace_force = never\nij_javascript_for_statement_new_line_after_left_paren = false\nij_javascript_for_statement_right_paren_on_new_line = false\nij_javascript_for_statement_wrap = off\nij_javascript_force_quote_style = true\nij_javascript_force_semicolon_style = true\nij_javascript_function_expression_brace_style = end_of_line\nij_javascript_if_brace_force = never\nij_javascript_import_merge_members = global\nij_javascript_import_prefer_absolute_path = true\nij_javascript_import_sort_members = true\nij_javascript_import_sort_module_name = false\nij_javascript_import_use_node_resolution = true\nij_javascript_imports_wrap = on_every_item\nij_javascript_indent_case_from_switch = true\nij_javascript_indent_chained_calls = true\nij_javascript_indent_package_children = 0\nij_javascript_jsx_attribute_value = braces\nij_javascript_keep_blank_lines_in_code = 1\nij_javascript_keep_first_column_comment = true\nij_javascript_keep_indents_on_empty_lines = false\nij_javascript_keep_line_breaks = true\nij_javascript_keep_simple_blocks_in_one_line = false\nij_javascript_keep_simple_methods_in_one_line = false\nij_javascript_line_comment_add_space = false\nij_javascript_line_comment_at_first_column = false\nij_javascript_method_brace_style = end_of_line\nij_javascript_method_call_chain_wrap = off\nij_javascript_method_parameters_new_line_after_left_paren = false\nij_javascript_method_parameters_right_paren_on_new_line = false\nij_javascript_method_parameters_wrap = off\nij_javascript_object_literal_wrap = on_every_item\nij_javascript_object_types_wrap = on_every_item\nij_javascript_parentheses_expression_new_line_after_left_paren = false\nij_javascript_parentheses_expression_right_paren_on_new_line = false\nij_javascript_place_assignment_sign_on_next_line = false\nij_javascript_prefer_as_type_cast = false\nij_javascript_prefer_explicit_types_function_expression_returns = false\nij_javascript_prefer_explicit_types_function_returns = false\nij_javascript_prefer_explicit_types_vars_fields = false\nij_javascript_prefer_parameters_wrap = false\nij_javascript_reformat_c_style_comments = false\nij_javascript_space_after_colon = true\nij_javascript_space_after_comma = true\nij_javascript_space_after_dots_in_rest_parameter = false\nij_javascript_space_after_generator_mult = true\nij_javascript_space_after_property_colon = true\nij_javascript_space_after_quest = true\nij_javascript_space_after_type_colon = true\nij_javascript_space_after_unary_not = true\nij_javascript_space_before_async_arrow_lparen = true\nij_javascript_space_before_catch_keyword = true\nij_javascript_space_before_catch_left_brace = true\nij_javascript_space_before_catch_parentheses = true\nij_javascript_space_before_class_lbrace = true\nij_javascript_space_before_class_left_brace = true\nij_javascript_space_before_colon = true\nij_javascript_space_before_comma = false\nij_javascript_space_before_do_left_brace = true\nij_javascript_space_before_else_keyword = true\nij_javascript_space_before_else_left_brace = true\nij_javascript_space_before_finally_keyword = true\nij_javascript_space_before_finally_left_brace = true\nij_javascript_space_before_for_left_brace = true\nij_javascript_space_before_for_parentheses = true\nij_javascript_space_before_for_semicolon = false\nij_javascript_space_before_function_left_parenth = true\nij_javascript_space_before_generator_mult = false\nij_javascript_space_before_if_left_brace = true\nij_javascript_space_before_if_parentheses = true\nij_javascript_space_before_method_call_parentheses = false\nij_javascript_space_before_method_left_brace = true\nij_javascript_space_before_method_parentheses = false\nij_javascript_space_before_property_colon = false\nij_javascript_space_before_quest = true\nij_javascript_space_before_switch_left_brace = true\nij_javascript_space_before_switch_parentheses = true\nij_javascript_space_before_try_left_brace = true\nij_javascript_space_before_type_colon = false\nij_javascript_space_before_unary_not = false\nij_javascript_space_before_while_keyword = true\nij_javascript_space_before_while_left_brace = true\nij_javascript_space_before_while_parentheses = true\nij_javascript_spaces_around_additive_operators = true\nij_javascript_spaces_around_arrow_function_operator = true\nij_javascript_spaces_around_assignment_operators = true\nij_javascript_spaces_around_bitwise_operators = true\nij_javascript_spaces_around_equality_operators = true\nij_javascript_spaces_around_logical_operators = true\nij_javascript_spaces_around_multiplicative_operators = true\nij_javascript_spaces_around_relational_operators = true\nij_javascript_spaces_around_shift_operators = true\nij_javascript_spaces_around_unary_operator = false\nij_javascript_spaces_within_array_initializer_brackets = false\nij_javascript_spaces_within_brackets = false\nij_javascript_spaces_within_catch_parentheses = false\nij_javascript_spaces_within_for_parentheses = false\nij_javascript_spaces_within_if_parentheses = false\nij_javascript_spaces_within_imports = true\nij_javascript_spaces_within_interpolation_expressions = true\nij_javascript_spaces_within_method_call_parentheses = false\nij_javascript_spaces_within_method_parentheses = false\nij_javascript_spaces_within_object_literal_braces = true\nij_javascript_spaces_within_object_type_braces = true\nij_javascript_spaces_within_parentheses = false\nij_javascript_spaces_within_switch_parentheses = false\nij_javascript_spaces_within_type_assertion = false\nij_javascript_spaces_within_union_types = true\nij_javascript_spaces_within_while_parentheses = false\nij_javascript_special_else_if_treatment = true\nij_javascript_ternary_operation_signs_on_next_line = false\nij_javascript_ternary_operation_wrap = off\nij_javascript_union_types_wrap = on_every_item\nij_javascript_use_chained_calls_group_indents = false\nij_javascript_use_double_quotes = false\nij_javascript_use_explicit_js_extension = auto\nij_javascript_use_path_mapping = always\nij_javascript_use_public_modifier = false\nij_javascript_use_semicolon_after_statement = false\nij_javascript_var_declaration_wrap = on_every_item\nij_javascript_while_brace_force = never\nij_javascript_while_on_new_line = false\nij_javascript_wrap_comments = false\n\n[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]\nij_continuation_indent_size = 4\nij_php_align_assignments = true\nij_php_align_class_constants = true\nij_php_align_enum_cases = true\nij_php_align_group_field_declarations = false\nij_php_align_inline_comments = false\nij_php_align_key_value_pairs = true\nij_php_align_match_arm_bodies = true\nij_php_align_multiline_array_initializer_expression = true\nij_php_align_multiline_binary_operation = false\nij_php_align_multiline_chained_methods = false\nij_php_align_multiline_extends_list = true\nij_php_align_multiline_for = false\nij_php_align_multiline_parameters = false\nij_php_align_multiline_parameters_in_calls = false\nij_php_align_multiline_ternary_operation = false\nij_php_align_named_arguments = true\nij_php_align_phpdoc_comments = false\nij_php_align_phpdoc_param_names = false\nij_php_anonymous_brace_style = end_of_line\nij_php_api_weight = 28\nij_php_array_initializer_new_line_after_left_brace = true\nij_php_array_initializer_right_brace_on_new_line = true\nij_php_array_initializer_wrap = on_every_item\nij_php_assignment_wrap = on_every_item\nij_php_attributes_wrap = split_into_lines\nij_php_author_weight = 3\nij_php_binary_operation_sign_on_next_line = true\nij_php_binary_operation_wrap = on_every_item\nij_php_blank_lines_after_class_header = 0\nij_php_blank_lines_after_function = 1\nij_php_blank_lines_after_imports = 1\nij_php_blank_lines_after_opening_tag = 1\nij_php_blank_lines_after_package = 1\nij_php_blank_lines_around_class = 1\nij_php_blank_lines_around_constants = 0\nij_php_blank_lines_around_enum_cases = 0\nij_php_blank_lines_around_field = 1\nij_php_blank_lines_around_method = 1\nij_php_blank_lines_before_class_end = 0\nij_php_blank_lines_before_imports = 1\nij_php_blank_lines_before_method_body = 0\nij_php_blank_lines_before_package = 1\nij_php_blank_lines_before_return_statement = 1\nij_php_blank_lines_between_imports = 1\nij_php_block_brace_style = end_of_line\nij_php_call_parameters_new_line_after_left_paren = true\nij_php_call_parameters_right_paren_on_new_line = true\nij_php_call_parameters_wrap = on_every_item\nij_php_catch_on_new_line = true\nij_php_category_weight = 28\nij_php_class_brace_style = next_line\nij_php_comma_after_last_argument = false\nij_php_comma_after_last_array_element = true\nij_php_comma_after_last_closure_use_var = false\nij_php_comma_after_last_match_arm = true\nij_php_comma_after_last_parameter = false\nij_php_concat_spaces = true\nij_php_copyright_weight = 4\nij_php_deprecated_weight = 0\nij_php_do_while_brace_force = always\nij_php_else_if_style = combine\nij_php_else_on_new_line = true\nij_php_example_weight = 28\nij_php_extends_keyword_wrap = normal\nij_php_extends_list_wrap = on_every_item\nij_php_fields_default_visibility = protected\nij_php_filesource_weight = 28\nij_php_finally_on_new_line = true\nij_php_for_brace_force = always\nij_php_for_statement_new_line_after_left_paren = false\nij_php_for_statement_right_paren_on_new_line = false\nij_php_for_statement_wrap = normal\nij_php_force_empty_methods_in_one_line = true\nij_php_force_short_declaration_array_style = true\nij_php_getters_setters_naming_style = camel_case\nij_php_getters_setters_order_style = getters_first\nij_php_global_weight = 28\nij_php_group_use_wrap = on_every_item\nij_php_if_brace_force = always\nij_php_if_lparen_on_next_line = true\nij_php_if_rparen_on_next_line = true\nij_php_ignore_weight = 28\nij_php_import_sorting = alphabetic\nij_php_indent_break_from_case = true\nij_php_indent_case_from_switch = true\nij_php_indent_code_in_php_tags = false\nij_php_internal_weight = 1\nij_php_keep_blank_lines_after_lbrace = 1\nij_php_keep_blank_lines_before_right_brace = 0\nij_php_keep_blank_lines_in_code = 1\nij_php_keep_blank_lines_in_declarations = 0\nij_php_keep_control_statement_in_one_line = false\nij_php_keep_first_column_comment = false\nij_php_keep_indents_on_empty_lines = false\nij_php_keep_line_breaks = true\nij_php_keep_rparen_and_lbrace_on_one_line = true\nij_php_keep_simple_classes_in_one_line = true\nij_php_keep_simple_methods_in_one_line = true\nij_php_lambda_brace_style = end_of_line\nij_php_license_weight = 5\nij_php_line_comment_add_space = false\nij_php_line_comment_at_first_column = false\nij_php_link_weight = 7\nij_php_lower_case_boolean_const = true\nij_php_lower_case_keywords = true\nij_php_lower_case_null_const = true\nij_php_method_brace_style = next_line\nij_php_method_call_chain_wrap = on_every_item\nij_php_method_parameters_new_line_after_left_paren = true\nij_php_method_parameters_right_paren_on_new_line = true\nij_php_method_parameters_wrap = on_every_item\nij_php_method_weight = 13\nij_php_modifier_list_wrap = false\nij_php_multiline_chained_calls_semicolon_on_new_line = false\nij_php_namespace_brace_style = 2\nij_php_new_line_after_php_opening_tag = true\nij_php_null_type_position = in_the_end\nij_php_package_weight = 28\nij_php_param_weight = 9\nij_php_parameters_attributes_wrap = split_into_lines\nij_php_parentheses_expression_new_line_after_left_paren = false\nij_php_parentheses_expression_right_paren_on_new_line = false\nij_php_phpdoc_blank_line_before_tags = true\nij_php_phpdoc_blank_lines_around_parameters = true\nij_php_phpdoc_keep_blank_lines = true\nij_php_phpdoc_param_spaces_between_name_and_description = 2\nij_php_phpdoc_param_spaces_between_tag_and_type = 2\nij_php_phpdoc_param_spaces_between_type_and_name = 2\nij_php_phpdoc_use_fqcn = true\nij_php_phpdoc_wrap_long_lines = true\nij_php_place_assignment_sign_on_next_line = false\nij_php_place_parens_for_constructor = 1\nij_php_property_read_weight = 11\nij_php_property_weight = 10\nij_php_property_write_weight = 12\nij_php_return_type_on_new_line = false\nij_php_return_weight = 15\nij_php_see_weight = 6\nij_php_since_weight = 2\nij_php_sort_phpdoc_elements = true\nij_php_space_after_colon = true\nij_php_space_after_colon_in_enum_backed_type = true\nij_php_space_after_colon_in_named_argument = true\nij_php_space_after_colon_in_return_type = true\nij_php_space_after_comma = true\nij_php_space_after_for_semicolon = true\nij_php_space_after_quest = true\nij_php_space_after_type_cast = true\nij_php_space_after_unary_not = true\nij_php_space_before_array_initializer_left_brace = true\nij_php_space_before_catch_keyword = true\nij_php_space_before_catch_left_brace = true\nij_php_space_before_catch_parentheses = true\nij_php_space_before_class_left_brace = true\nij_php_space_before_closure_left_parenthesis = true\nij_php_space_before_colon = true\nij_php_space_before_colon_in_enum_backed_type = false\nij_php_space_before_colon_in_named_argument = false\nij_php_space_before_colon_in_return_type = false\nij_php_space_before_comma = false\nij_php_space_before_do_left_brace = true\nij_php_space_before_else_keyword = true\nij_php_space_before_else_left_brace = true\nij_php_space_before_finally_keyword = true\nij_php_space_before_finally_left_brace = true\nij_php_space_before_for_left_brace = true\nij_php_space_before_for_parentheses = true\nij_php_space_before_for_semicolon = false\nij_php_space_before_if_left_brace = true\nij_php_space_before_if_parentheses = true\nij_php_space_before_method_call_parentheses = false\nij_php_space_before_method_left_brace = true\nij_php_space_before_method_parentheses = false\nij_php_space_before_quest = true\nij_php_space_before_short_closure_left_parenthesis = true\nij_php_space_before_switch_left_brace = true\nij_php_space_before_switch_parentheses = true\nij_php_space_before_try_left_brace = true\nij_php_space_before_unary_not = false\nij_php_space_before_while_keyword = true\nij_php_space_before_while_left_brace = true\nij_php_space_before_while_parentheses = true\nij_php_space_between_ternary_quest_and_colon = false\nij_php_spaces_around_additive_operators = true\nij_php_spaces_around_arrow = false\nij_php_spaces_around_assignment_in_declare = false\nij_php_spaces_around_assignment_operators = true\nij_php_spaces_around_bitwise_operators = true\nij_php_spaces_around_equality_operators = true\nij_php_spaces_around_logical_operators = true\nij_php_spaces_around_multiplicative_operators = true\nij_php_spaces_around_null_coalesce_operator = true\nij_php_spaces_around_pipe_in_union_type = false\nij_php_spaces_around_relational_operators = true\nij_php_spaces_around_shift_operators = true\nij_php_spaces_around_unary_operator = false\nij_php_spaces_around_var_within_brackets = false\nij_php_spaces_within_array_initializer_braces = false\nij_php_spaces_within_brackets = false\nij_php_spaces_within_catch_parentheses = false\nij_php_spaces_within_for_parentheses = false\nij_php_spaces_within_if_parentheses = false\nij_php_spaces_within_method_call_parentheses = false\nij_php_spaces_within_method_parentheses = false\nij_php_spaces_within_parentheses = false\nij_php_spaces_within_short_echo_tags = true\nij_php_spaces_within_switch_parentheses = false\nij_php_spaces_within_while_parentheses = false\nij_php_special_else_if_treatment = true\nij_php_subpackage_weight = 28\nij_php_ternary_operation_signs_on_next_line = true\nij_php_ternary_operation_wrap = on_every_item\nij_php_throws_weight = 14\nij_php_todo_weight = 28\nij_php_treat_multiline_arrays_and_lambdas_multiline = false\nij_php_unknown_tag_weight = 28\nij_php_upper_case_boolean_const = false\nij_php_upper_case_null_const = false\nij_php_uses_weight = 28\nij_php_var_weight = 28\nij_php_variable_naming_style = camel_case\nij_php_version_weight = 8\nij_php_while_brace_force = always\nij_php_while_on_new_line = true\n\n[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,composer.lock,jest.config}]\nij_continuation_indent_size = 4\nij_json_array_wrapping = on_every_item\nij_json_keep_blank_lines_in_code = 1\nij_json_keep_indents_on_empty_lines = false\nij_json_keep_line_breaks = true\nij_json_keep_trailing_comma = false\nij_json_object_wrapping = on_every_item\nij_json_property_alignment = do_not_align\nij_json_space_after_colon = true\nij_json_space_after_comma = true\nij_json_space_before_colon = false\nij_json_space_before_comma = false\nij_json_spaces_within_braces = true\nij_json_spaces_within_brackets = false\nij_json_wrap_long_lines = false\n\n[{*.htm,*.html,*.sht,*.shtm,*.shtml}]\nij_continuation_indent_size = 4\nij_visual_guides = 160\nij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3\nij_html_align_attributes = false\nij_html_align_text = false\nij_html_attribute_wrap = on_every_item\nij_html_block_comment_add_space = false\nij_html_block_comment_at_first_column = true\nij_html_do_not_align_children_of_min_lines = 0\nij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p\nij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot\nij_html_enforce_quotes = true\nij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var\nij_html_keep_blank_lines = 2\nij_html_keep_indents_on_empty_lines = false\nij_html_keep_line_breaks = true\nij_html_keep_line_breaks_in_text = true\nij_html_keep_whitespaces = false\nij_html_keep_whitespaces_inside = span,pre,textarea\nij_html_line_comment_at_first_column = true\nij_html_new_line_after_last_attribute = never\nij_html_new_line_before_first_attribute = when_multiline\nij_html_quote_style = double\nij_html_remove_new_line_before_tags = br\nij_html_space_after_tag_name = false\nij_html_space_around_equality_in_attribute = false\nij_html_space_inside_empty_tag = true\nij_html_text_wrap = off\n\n[{*.http,*.rest}]\nindent_size = 0\nij_continuation_indent_size = 4\nij_http request_call_parameters_wrap = on_every_item\n\n[{*.markdown,*.md}]\nij_markdown_force_one_space_after_blockquote_symbol = true\nij_markdown_force_one_space_after_header_symbol = true\nij_markdown_force_one_space_after_list_bullet = true\nij_markdown_force_one_space_between_words = true\nij_markdown_format_tables = true\nij_markdown_insert_quote_arrows_on_wrap = true\nij_markdown_keep_indents_on_empty_lines = false\nij_markdown_keep_line_breaks_inside_text_blocks = true\nij_markdown_max_lines_around_block_elements = 1\nij_markdown_max_lines_around_header = 1\nij_markdown_max_lines_between_paragraphs = 1\nij_markdown_min_lines_around_block_elements = 1\nij_markdown_min_lines_around_header = 2\nij_markdown_min_lines_between_paragraphs = 1\nij_markdown_wrap_text_if_long = true\nij_markdown_wrap_text_inside_blockquotes = true\n\n[{*.yaml,*.yml}]\nij_yaml_align_values_properties = do_not_align\nij_yaml_autoinsert_sequence_marker = true\nij_yaml_block_mapping_on_new_line = false\nij_yaml_indent_sequence_value = true\nij_yaml_keep_indents_on_empty_lines = false\nij_yaml_keep_line_breaks = true\nij_yaml_sequence_on_new_line = true\nij_yaml_space_before_colon = false\nij_yaml_spaces_within_braces = true\nij_yaml_spaces_within_brackets = true\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n\n.github/ export-ignore\ndocs/ export-ignore\ntests/ export-ignore\n\n*.stub linguist-language=php\n\n.editorconfig export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n\nphpunit.xml export-ignore\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug Report\ndescription: Report a bug or other issue\n\nbody:\n    -   type: markdown\n        attributes:\n            value: |\n                Thanks for taking the time to fill out this bug report!\n\n                ⚠️Review existing issues to see whether someone else has already reported your issue.\n\n    -   type: textarea\n        id: environment\n        attributes:\n            label: Environment\n            description: |\n                Tip: Use the `composer info dragon-code/laravel-deploy-operations` command to get information for Laravel Lang.\n                Tip: Use the `php artisan --version` command to get information for Laravel Framework.\n                Tip: Use the `php -v` command to get information for PHP.\n            value: |\n                - PHP Version:\n                - Database Driver & Version:\n                - Deploy Operations Version:\n                - Laravel Version:\n        validations:\n            required: true\n\n    -   type: textarea\n        id: description\n        attributes:\n            label: Issue description\n            description: |\n                Be as specific and detailed as possible to help us triaging your issue. Screenshots and/or animations can be very useful in helping to understand the issue you're facing.\n\n                Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.\n                Tip: You can use https://www.screentogif.com to record animations and videos.\n        validations:\n            required: true\n\n    -   type: textarea\n        id: steps\n        attributes:\n            label: Steps to reproduce\n            description: Take some time to try and reproduce the issue, then explain how to do so here.\n        validations:\n            required: true\n\n    -   type: markdown\n        attributes:\n            value: |\n                ❤️ The Dragon Code? Please consider supporting [`our collective`](https://boosty.to/dragon-code).\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n    -   name: Laravel issue\n        url: https://github.com/laravel/framework/issues\n        about: 'If you have a question about your Laravel implementation, ask it in your Laravel project.'\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: Feature Proposal\ndescription: Propose a new feature\n\nbody:\n    -   type: textarea\n        id: description\n        attributes:\n            label: Feature description\n            description: |\n                Think through your proposal and describe it clearly.\n\n                Note that features are only added to the most recent version of Laravel Lang.\n        validations:\n            required: true\n\n    -   type: markdown\n        attributes:\n            value: |\n                ❤️ The Dragon Code? Please consider supporting [`our collective`](https://boosty.to/dragon-code).\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\nPull requests without a descriptive title, thorough description, or tests will be closed.\n\nIn addition, please describe the benefit to end users; the reasons it does not break any existing features; how it makes building web applications easier, etc.\n-->\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n    - package-ecosystem: github-actions\n      directory: /\n      schedule:\n          interval: daily\n      labels:\n          - dependabot\n"
  },
  {
    "path": ".github/preview-updater.yml",
    "content": "image:\n    parameters:\n        title: 'Deploy Operations'\n"
  },
  {
    "path": ".github/workflows/code-style.yml",
    "content": "name: Code Style\n\non: [ push, pull_request ]\n\npermissions: write-all\n\njobs:\n    check:\n        uses: TheDragonCode/.github/.github/workflows/code-style.yml@main\n"
  },
  {
    "path": ".github/workflows/docs.yml",
    "content": "name: Documentation\n\non:\n    push:\n    workflow_dispatch:\n\npermissions:\n    id-token: write\n    pages: write\n\nenv:\n    COMPOSER_TOKEN: ${{ secrets.COMPOSER_TOKEN }}\n    ARTIFACT_DOCS: webHelpDO2-all.zip\n    INSTANCE: docs/do\n    DOMAIN_NAME: deploy-operations.dragon-code.pro\n    BUILDER_VERSION: 2025.04.8412\n\njobs:\n    build:\n        name: Build application\n        runs-on: ubuntu-latest\n\n        steps:\n            -   uses: actions/checkout@v6\n                with:\n                    fetch-depth: 0\n\n            -   name: Build documentation\n                uses: JetBrains/writerside-github-action@v4\n                with:\n                    instance: ${{ env.INSTANCE }}\n                    artifact: ${{ env.ARTIFACT_DOCS }}\n                    docker-version: ${{ env.BUILDER_VERSION }}\n\n            -   name: Upload artifacts\n                uses: actions/upload-artifact@v7\n                with:\n                    name: docs\n                    path: |\n                        artifacts/${{ env.ARTIFACT_DOCS }}\n                        artifacts/report.json\n                    retention-days: 7\n\n    test:\n        needs: build\n        name: Testing\n        runs-on: ubuntu-latest\n\n        steps:\n            -   name: Download docs artifact\n                uses: actions/download-artifact@v8\n                with:\n                    name: docs\n                    path: artifacts\n\n            -   name: Test documentation\n                uses: JetBrains/writerside-checker-action@v1\n                with:\n                    instance: ${{ env.INSTANCE }}\n\n    robots:\n        needs: build\n        name: Generate robots.txt\n        runs-on: ubuntu-latest\n        if: github.ref == 'refs/heads/main'\n\n        steps:\n            -   name: Create robots.txt\n                run: |\n                    touch robots.txt\n                    echo \"User-Agent: *\" >> robots.txt\n                    echo \"Disallow: \" >> robots.txt\n                    echo \"Host: https://${{ env.DOMAIN_NAME }}\" >> robots.txt\n                    echo \"Sitemap: https://${{ env.DOMAIN_NAME }}/sitemap.xml\" >> robots.txt\n\n            -   name: Upload artifacts\n                uses: actions/upload-artifact@v7\n                with:\n                    name: robots\n                    path: robots.txt\n                    retention-days: 7\n\n    deploy-pages:\n        environment:\n            name: deploy\n            url: ${{ steps.deployment.outputs.page_url }}\n\n        needs:\n            - test\n            - robots\n\n        name: Deploy to pages\n        runs-on: ubuntu-latest\n        if: github.ref == 'refs/heads/main'\n\n        steps:\n            -   name: Download docs artifact\n                uses: actions/download-artifact@v8\n                with:\n                    name: docs\n\n            -   name: Download robots artifact\n                uses: actions/download-artifact@v8\n                with:\n                    name: robots\n\n            -   name: Unzip artifact\n                run: unzip -O UTF-8 -qq '${{ env.ARTIFACT_DOCS }}' -d dir\n\n            -   name: Move robots\n                run: |\n                    sudo mv robots.txt dir/robots.txt\n\n            -   name: Setup Pages\n                uses: actions/configure-pages@v6\n\n            -   name: Upload artifact\n                uses: actions/upload-pages-artifact@v5\n                with:\n                    path: dir\n\n            -   name: Deploy to GitHub Pages\n                id: deployment\n                uses: actions/deploy-pages@v5\n"
  },
  {
    "path": ".github/workflows/license.yml",
    "content": "name: Update license\n\non:\n  schedule:\n    - cron: '0 3 1 1 *'\n  workflow_dispatch:\n\njobs:\n  Update:\n    uses: TheDragonCode/.github/.github/workflows/license.yml@main"
  },
  {
    "path": ".github/workflows/preview.yml",
    "content": "name: Preview Updater\n\non:\n    schedule:\n        -   cron: '20 2 * * *'\n    workflow_dispatch:\n\npermissions:\n    contents: write\n    pull-requests: write\n\njobs:\n    preview:\n        uses: TheDragonCode/.github/.github/workflows/preview.yml@main"
  },
  {
    "path": ".github/workflows/release-drafter.yml",
    "content": "name: Release Drafter\n\non:\n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\njobs:\n    Update:\n        uses: TheDragonCode/.github/.github/workflows/release-drafter.yml@main\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Tests\n\non: [ push, pull_request ]\n\njobs:\n    build:\n        runs-on: ubuntu-latest\n\n        strategy:\n            fail-fast: true\n            matrix:\n                php: [ \"8.2\", \"8.3\", \"8.4\", \"8.5\" ]\n                laravel: [ \"11.0\", \"12.0\", \"13.0\" ]\n                exclude:\n                    - laravel: \"13.0\"\n                      php: \"8.2\"\n\n        name: PHP ${{ matrix.php }}, Laravel ${{ matrix.laravel }}\n\n        steps:\n            -   name: Checkout code\n                uses: actions/checkout@v6\n\n            -   name: Setup PHP\n                uses: shivammathur/setup-php@v2\n                with:\n                    php-version: ${{ matrix.php }}\n                    extensions: curl, mbstring, zip, pcntl, pdo, pdo_sqlite, iconv\n                    coverage: xdebug\n\n            -   name: Install dependencies\n                run: composer require --dev laravel/framework:^${{ matrix.laravel }}\n\n            -   name: Execute tests\n                run: sudo vendor/bin/phpunit\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea/\n_site/\nbuild/\nnode_modules/\ntmp/\nvendor/\n\n.cache\n.DS_Store\n.env\n.php_cs.cache\n.phpintel\n.temp\n\n*.bak\n*.cache\n*.clover\n*.orig\n\ncomposer.lock\npackage-lock.json\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020-2026 Andrey Helldar\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# 🚀 Laravel Deploy Operations\n\n<picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://banners.beyondco.de/Laravel%20Deploy%20Operations.png?pattern=topography&style=style_2&fontSize=100px&md=1&showWatermark=1&theme=dark&packageManager=composer+require&packageName=dragon-code%2Flaravel-deploy-operations&description=Performing+any+actions+during+the+deployment+process&images=https%3A%2F%2Flaravel.com%2Fimg%2Flogomark.min.svg\">\n    <img src=\"https://banners.beyondco.de/Deploy%20Operations.png?pattern=topography&style=style_2&fontSize=100px&md=1&showWatermark=1&theme=light&packageManager=composer+require&packageName=dragon-code%2Flaravel-deploy-operations&description=Performing+any+actions+during+the+deployment+process&images=https%3A%2F%2Flaravel.com%2Fimg%2Flogomark.min.svg\" alt=\"Laravel Deploy Operations\">\n</picture>\n\n[![Stable Version][badge_stable]][link_packagist]\n[![Total Downloads][badge_downloads]][link_packagist]\n[![Github Workflow Status][badge_build]][link_build]\n[![License][badge_license]][link_license]\n\n⚡ **Performing any actions during the deployment process**\n\nCreate specific classes for a one-time or more-time usage, that can be executed automatically after each deployment.\nPerfect for seeding or updating some data instantly after some database changes, feature updates, or perform any\nactions.\n\nThis package is for you if...\n\n- you regularly need to update specific data after you deploy new code\n- you often perform jobs after deployment\n- you sometimes forget to execute that one specific job and stuff gets crazy\n- your code gets cluttered with jobs that are not being used anymore\n- your co-workers always need to be reminded to execute that one job after some database changes\n- you often seed or process data in a migration file (which is a big no-no!)\n\n## Installation\n\nTo get the latest version of **Deploy Operations**, simply require the project using [Composer](https://getcomposer.org):\n\n```Bash\ncomposer require dragon-code/laravel-deploy-operations\n```\n\n## Documentation\n\n📚 [Check out the full documentation to learn everything that Laravel Deploy Operations has to offer.][link_website]\n\n## Basic Usage\n\nCreate your first operation using `php artisan make:operation` console command and define the actions it should\nperform.\n\n```php\nuse App\\Models\\Article;\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke(): void\n    {\n        Article::query()\n            ->lazyById(chunkSize: 100, column: 'id')\n            ->each->update(['is_active' => true]);\n\n        // and/or any actions...\n    }\n};\n```\n\nNext, you can run the console command to start operations:\n\n```Bash\nphp artisan operations\n```\n\n## Downloads Stats\n\nThis project has gone the way of several names, and here are the number of downloads of each of them:\n\n- ![](https://img.shields.io/packagist/dt/dragon-code/laravel-deploy-operations?style=flat-square&label=dragon-code%2Flaravel-deploy-operations)\n- ![](https://img.shields.io/packagist/dt/dragon-code/laravel-actions?style=flat-square&label=dragon-code%2Flaravel-actions)\n- ![](https://img.shields.io/packagist/dt/dragon-code/laravel-migration-actions?style=flat-square&label=dragon-code%2Flaravel-migration-actions)\n- ![](https://img.shields.io/packagist/dt/andrey-helldar/laravel-actions?style=flat-square&label=andrey-helldar%2Flaravel-actions)\n\n## License\n\nThis package is licensed under the [MIT License](LICENSE).\n\n\n[badge_build]:          https://img.shields.io/github/actions/workflow/status/TheDragonCode/laravel-deploy-operations/tests.yml?style=flat-square\n\n[badge_downloads]:      https://img.shields.io/packagist/dt/dragon-code/laravel-deploy-operations.svg?style=flat-square\n\n[badge_license]:        https://img.shields.io/packagist/l/dragon-code/laravel-deploy-operations.svg?style=flat-square\n\n[badge_stable]:         https://img.shields.io/github/v/release/TheDragonCode/laravel-deploy-operations?label=packagist&style=flat-square\n\n[link_build]:           https://github.com/TheDragonCode/laravel-deploy-operations/actions\n\n[link_license]:         LICENSE\n\n[link_packagist]:       https://packagist.org/packages/dragon-code/laravel-deploy-operations\n\n[link_website]:         https://deploy-operations.dragon-code.pro\n"
  },
  {
    "path": "biome.json",
    "content": "{\n    \"$schema\": \"./node_modules/@biomejs/biome/configuration_schema.json\",\n    \"vcs\": {\n        \"enabled\": false,\n        \"clientKind\": \"git\",\n        \"useIgnoreFile\": false\n    },\n    \"files\": {\n        \"ignoreUnknown\": false,\n        \"includes\": [\n            \"**\",\n            \"!node_modules\",\n            \"!vendor\",\n            \"!composer.json\",\n            \"!composer.lock\",\n            \"!package.json\",\n            \"!package-lock.json\",\n            \"!**/analytics.*\",\n            \"!**/metrics.*\",\n            \"!coverage\",\n            \"!dist\",\n            \"!build\",\n            \"!public\"\n        ]\n    },\n    \"formatter\": {\n        \"enabled\": true,\n        \"indentStyle\": \"space\",\n        \"indentWidth\": 4\n    },\n    \"linter\": {\n        \"enabled\": true,\n        \"rules\": {\n            \"recommended\": true\n        }\n    },\n    \"javascript\": {\n        \"formatter\": {\n            \"quoteStyle\": \"double\"\n        }\n    },\n    \"json\": {\n        \"formatter\": {\n            \"enabled\": true,\n            \"bracketSpacing\": true,\n            \"expand\": \"always\"\n        },\n        \"parser\": {\n            \"allowComments\": true\n        }\n    },\n    \"assist\": {\n        \"enabled\": true,\n        \"actions\": {\n            \"source\": {\n                \"organizeImports\": \"on\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"dragon-code/laravel-deploy-operations\",\n    \"description\": \"Performing any actions during the deployment process\",\n    \"license\": \"MIT\",\n    \"type\": \"library\",\n    \"keywords\": [\n        \"laravel\",\n        \"deploy\",\n        \"deployment\",\n        \"operations\",\n        \"action\",\n        \"actions\",\n        \"migration\",\n        \"migrations\",\n        \"dragon-code\",\n        \"dragon\",\n        \"andrey-helldar\"\n    ],\n    \"authors\": [\n        {\n            \"name\": \"Andrey Helldar\",\n            \"email\": \"helldar@dragon-code.pro\",\n            \"homepage\": \"https://dragon-code.pro\"\n        }\n    ],\n    \"support\": {\n        \"issues\": \"https://github.com/TheDragonCode/laravel-deploy-operations/issues\",\n        \"source\": \"https://github.com/TheDragonCode/laravel-deploy-operations\"\n    },\n    \"funding\": [\n        {\n            \"type\": \"boosty\",\n            \"url\": \"https://boosty.to/dragon-code\"\n        },\n        {\n            \"type\": \"yoomoney\",\n            \"url\": \"https://yoomoney.ru/to/410012608840929\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^8.2\",\n        \"composer-runtime-api\": \"^2.2\",\n        \"dragon-code/support\": \"^6.6\",\n        \"laravel/framework\": \"^11.0 || ^12.0 || ^13.0\",\n        \"laravel/prompts\": \">=0.1\",\n        \"spatie/laravel-data\": \"^4.14\"\n    },\n    \"require-dev\": {\n        \"mockery/mockery\": \"^1.3.1\",\n        \"nesbot/carbon\": \"^2.62.1 || ^3.0\",\n        \"orchestra/testbench\": \"^9.0 || ^10.0 || ^11.0\",\n        \"phpunit/phpunit\": \"^11.0 || ^12.0\"\n    },\n    \"conflict\": {\n        \"andrey-helldar/laravel-actions\": \"*\",\n        \"dragon-code/laravel-actions\": \"*\",\n        \"dragon-code/laravel-migration-actions\": \"*\"\n    },\n    \"suggest\": {\n        \"dragon-code/laravel-data-dumper\": \"Required if you want to save the execution state using the `schema:dump` console command\"\n    },\n    \"minimum-stability\": \"stable\",\n    \"prefer-stable\": true,\n    \"autoload\": {\n        \"psr-4\": {\n            \"DragonCode\\\\LaravelDeployOperations\\\\\": \"src/\"\n        },\n        \"files\": [\n            \"src/helpers.php\"\n        ]\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Tests\\\\\": \"tests/\"\n        }\n    },\n    \"config\": {\n        \"allow-plugins\": {\n            \"ergebnis/composer-normalize\": true,\n            \"laravel/pint\": true,\n            \"symfony/thanks\": true\n        },\n        \"preferred-install\": \"dist\",\n        \"sort-packages\": true\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"providers\": [\n                \"DragonCode\\\\LaravelDeployOperations\\\\ServiceProvider\"\n            ]\n        }\n    }\n}\n"
  },
  {
    "path": "config/deploy-operations.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    /*\n    |--------------------------------------------------------------------------\n    | Operations Repository Connection\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the database connection used to store the table\n    | of executed operations.\n    |\n    */\n\n    'connection' => env('DB_CONNECTION'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Operations Repository Table\n    |--------------------------------------------------------------------------\n    |\n    | This table keeps track of all the operations that have already run for\n    | your application. Using this information, we can determine which of\n    | the operations on disk haven't actually been run in the database.\n    |\n    */\n\n    'table' => 'operations',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Database Transactions\n    |--------------------------------------------------------------------------\n    |\n    | This setting defines the rules for working with database transactions.\n    | This specifies a common value for all operations, but you can override this\n    | value directly in the class of the operation itself.\n    */\n\n    'transactions' => [\n        // Determines whether the use of database transactions is enabled.\n\n        'enabled' => false,\n\n        // The number of attempts to execute a request within a transaction before throwing an error.\n\n        'attempts' => 1,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Operations Path\n    |--------------------------------------------------------------------------\n    |\n    | This option defines the path to the operation directory.\n    |\n    */\n\n    'path' => base_path('operations'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Path Exclusion\n    |--------------------------------------------------------------------------\n    |\n    | This option determines which directory and/or file paths should be\n    | excluded when processing files.\n    |\n    | Valid values: array, string or null\n    |\n    | Specify `null` to disable.\n    |\n    | For example,\n    |    ['foo', 'bar']\n    |    'foo'\n    |    null\n    |\n    */\n\n    'exclude' => null,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Asynchronous settings\n    |--------------------------------------------------------------------------\n    |\n    | Defines whether the operation will run synchronously or asynchronously.\n    |\n    | When this option is activated, each operation will be performed through jobs.\n    */\n\n    'async' => false,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Queue\n    |--------------------------------------------------------------------------\n    |\n    | This option specifies the queue settings that will process\n    | asynchronous operations.\n    |\n    */\n\n    'queue' => [\n        /*\n        |--------------------------------------------------------------------------\n        | Queue Connection\n        |--------------------------------------------------------------------------\n        |\n        | This parameter defines the default connection.\n        |\n        */\n\n        'connection' => env('DEPLOY_OPERATIONS_QUEUE_CONNECTION', env('QUEUE_CONNECTION', 'sync')),\n\n        /*\n        |--------------------------------------------------------------------------\n        | Queue Name\n        |--------------------------------------------------------------------------\n        |\n        | This parameter specifies the name of the queue to which asynchronous\n        | jobs will be sent.\n        |\n        */\n\n        'name' => env('DEPLOY_OPERATIONS_QUEUE_NAME'),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Show\n    |--------------------------------------------------------------------------\n    |\n    | This option determines the display settings for various information messages.\n    |\n    */\n\n    'show' => [\n        /*\n        |--------------------------------------------------------------------------\n        | Full Path\n        |--------------------------------------------------------------------------\n        |\n        | This parameter determines how exactly the link to the created file should\n        | be displayed - the full path to the file or a relative one.\n        |\n        */\n\n        'full_path' => (bool) env('DEPLOY_OPERATIONS_SHOW_FULL_PATH', false),\n    ],\n];\n"
  },
  {
    "path": "database/migrations/2022_08_18_180137_change_migration_actions_table.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        if ($this->hasTable()) {\n            Schema::table($this->table(), function (Blueprint $table) {\n                if ($this->hasColumn('migration') && $this->doesntHaveColumn('action')) {\n                    $table->renameColumn('migration', 'action');\n                }\n\n                $table->unsignedInteger('batch')->change();\n            });\n        }\n    }\n\n    public function down(): void\n    {\n        if ($this->hasTable()) {\n            Schema::table($this->table(), function (Blueprint $table) {\n                $table->renameColumn('action', 'migration');\n\n                $table->integer('batch')->change();\n            });\n        }\n    }\n\n    protected function hasTable(): bool\n    {\n        return Schema::hasTable($this->table());\n    }\n\n    protected function hasColumn(string $column): bool\n    {\n        return Schema::hasColumn($this->table(), $column);\n    }\n\n    protected function doesntHaveColumn(string $column): bool\n    {\n        return ! $this->hasColumn($column);\n    }\n\n    protected function table(): string\n    {\n        return app(ConfigData::class)->table;\n    }\n};\n"
  },
  {
    "path": "database/migrations/2023_01_21_172923_rename_migrations_actions_table_to_actions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        if (Schema::hasTable('migration_actions') && $this->doesntSame('migration_actions', $this->table())) {\n            $this->validateTable($this->table());\n\n            Schema::rename('migration_actions', $this->table());\n        }\n    }\n\n    public function down(): void\n    {\n        if (Schema::hasTable($this->table()) && $this->doesntSame('migration_actions', $this->table())) {\n            $this->validateTable('migration_actions');\n\n            Schema::rename($this->table(), 'migration_actions');\n        }\n    }\n\n    protected function validateTable(string $name): void\n    {\n        if (Schema::hasTable($name)) {\n            throw new RuntimeException(sprintf('A table named [%s] already exists. Change the table name settings in the [%s] configuration file.', $name, 'config/actions.php'));\n        }\n    }\n\n    protected function doesntSame(string $first, string $second): bool\n    {\n        return $first !== $second;\n    }\n\n    protected function table(): string\n    {\n        return app(ConfigData::class)->table;\n    }\n};\n"
  },
  {
    "path": "database/migrations/2024_05_21_112438_rename_actions_table_to_operations.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        if (Schema::hasTable('actions') && $this->doesntSame('actions', $this->table())) {\n            $this->validateTable($this->table());\n\n            Schema::rename('actions', $this->table());\n        }\n    }\n\n    public function down(): void\n    {\n        if (Schema::hasTable($this->table()) && $this->doesntSame('actions', $this->table())) {\n            $this->validateTable('actions');\n\n            Schema::rename($this->table(), 'actions');\n        }\n    }\n\n    protected function validateTable(string $name): void\n    {\n        if (Schema::hasTable($name)) {\n            throw new RuntimeException(sprintf('A table named [%s] already exists. Change the table name settings in the [%s] configuration file.', $name, 'config/deploy-operations.php'));\n        }\n    }\n\n    protected function doesntSame(string $first, string $second): bool\n    {\n        return $first !== $second;\n    }\n\n    protected function table(): string\n    {\n        return app(ConfigData::class)->table;\n    }\n};\n"
  },
  {
    "path": "database/migrations/2024_05_21_114318_rename_column_in_operations_table.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        $this->rename('action', 'operation');\n    }\n\n    public function down(): void\n    {\n        $this->rename('operation', 'action');\n    }\n\n    protected function rename(string $from, string $to): void\n    {\n        if (Schema::hasColumn($this->table(), $from)) {\n            Schema::table($this->table(), fn (Blueprint $table) => $table->renameColumn($from, $to));\n        }\n    }\n\n    protected function table(): string\n    {\n        return app(ConfigData::class)->table;\n    }\n};\n"
  },
  {
    "path": "docs/cfg/buildprofiles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE buildprofiles SYSTEM \"https://resources.jetbrains.com/writerside/1.0/build-profiles.dtd\">\n<buildprofiles xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/build-profiles.xsd\"\n               xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\n    <variables>\n        <generate-canonicals>true</generate-canonicals>\n        <locale-code>en_US</locale-code>\n        <header-logo>logo.svg</header-logo>\n        <!-- <og-image> -->\n        <!--     https://raw.githubusercontent.com/Laravel-Lang/docs/main/docs/images/social-logo.png -->\n        <!-- </og-image> -->\n        <web-root>https://deploy-operations.dragon-code.pro</web-root>\n        <enable-contribution>true</enable-contribution>\n        <code-soft-wrap>true</code-soft-wrap>\n        <contribute-url>\n            https://github.com/TheDragonCode/laravel-deploy-operations/edit/main/docs/\n        </contribute-url>\n        <custom-favicons>\n            logo.svg,logo.svg,logo.svg,logo.svg\n        </custom-favicons>\n        <!-- <analytics-head-script-file> -->\n        <!--     analytics.html -->\n        <!-- </analytics-head-script-file> -->\n        <versions-switcher>\n            https://raw.githubusercontent.com/TheDragonCode/laravel-deploy-operations/refs/heads/main/docs/versions.json\n        </versions-switcher>\n        <content-max-width>\n            1280\n        </content-max-width>\n    </variables>\n    <build-profile instance=\"do\">\n        <variables>\n            <product-web-url>https://deploy-operations.dragon-code.pro/</product-web-url>\n            <noindex-content>false</noindex-content>\n            <!-- <og-image> -->\n            <!--     https://raw.githubusercontent.com/TheDragonCode/laravel-deploy-operations/main/docs/images/social-logo.png -->\n            <!-- </og-image> -->\n        </variables>\n    </build-profile>\n    <sitemap priority=\"0.5\" change-frequency=\"weekly\" />\n    <footer>\n        <social type=\"github\" href=\"https://github.com/TheDragonCode\">\n            GitHub\n        </social>\n        <link href=\"https://boosty.to/dragon-code\">\n            Boosty\n        </link>\n        <link href=\"https://github.com/TheDragonCode/laravel-deploy-operations/issues\">\n            Issues\n        </link>\n    </footer>\n</buildprofiles>\n"
  },
  {
    "path": "docs/do.tree",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE instance-profile\n        SYSTEM \"https://resources.jetbrains.com/writerside/1.0/product-profile.dtd\">\n\n<instance-profile id=\"do\"\n                  name=\"Laravel Deploy Operations\"\n                  start-page=\"introduction.topic\">\n\n    <toc-element toc-title=\"Prologue\">\n        <toc-element topic=\"introduction.topic\" />\n        <toc-element toc-title=\"Upgrade Guide\" sort-children=\"descending\">\n            <toc-element topic=\"upgrade-7.topic\" toc-title=\"Upgrade to 7.x\" />\n            <toc-element topic=\"upgrade-6.topic\" toc-title=\"Upgrade to 6.x\" />\n            <toc-element topic=\"upgrade-5.topic\" toc-title=\"Upgrade to 5.x\" />\n            <toc-element topic=\"upgrade-4.topic\" toc-title=\"Upgrade to 4.x\" />\n            <toc-element topic=\"upgrade-3.topic\" toc-title=\"Upgrade to 3.x\" />\n        </toc-element>\n    </toc-element>\n    <toc-element toc-title=\"Getting Started\">\n        <toc-element topic=\"installation.topic\" />\n        <toc-element topic=\"usage.topic\" />\n    </toc-element>\n    <toc-element toc-title=\"Guide\">\n        <toc-element topic=\"running-operations.topic\" />\n        <toc-element topic=\"creating-operations.topic\" />\n        <toc-element topic=\"rolling-back-operations.topic\" />\n        <toc-element topic=\"operations-status.topic\" />\n        <toc-element topic=\"customize-stub.topic\" />\n    </toc-element>\n    <toc-element toc-title=\"Helpers\">\n        <toc-element topic=\"artisan-commands.topic\" />\n        <toc-element topic=\"operation-helper.topic\" />\n        <toc-element topic=\"events.topic\" />\n        <toc-element topic=\"execution-status.topic\" />\n    </toc-element>\n    <toc-element toc-title=\"Extras\">\n        <toc-element topic=\"database-data-dumper.topic\" />\n    </toc-element>\n</instance-profile>\n"
  },
  {
    "path": "docs/docs_libraries.tree",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE instance-profile\n        SYSTEM \"https://resources.jetbrains.com/writerside/1.0/product-profile.dtd\">\n\n<instance-profile id=\"docs_libraries\"\n                  name=\"docs_libraries\" is-library=\"true\" start-page=\"snippets_composer.topic\">\n\n    <toc-element topic=\"snippets_composer.topic\" />\n</instance-profile>\n"
  },
  {
    "path": "docs/snippets/actual_file_names.sh",
    "content": "# actual file names\n2022_10_14_000001_test1      # 1\n2022_10_14_000004_test4      # 4\nbar/2022_10_14_000003_test3  # 3\nfoo/2022_10_14_000002_test2  # 2\n"
  },
  {
    "path": "docs/snippets/ask.sh",
    "content": "php artisan make:operation\n  Creating an operation \n\n ┌ What should the operation be named? ─────────────────────────┐\n │ E.g. activate articles                                       │\n └──────────────────────────────────────────────────────────────┘\n  Press Enter to autodetect\n"
  },
  {
    "path": "docs/snippets/async.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke()\n    {\n        // some\n    }\n\n    public function shouldBeAsync(): bool\n    {\n        return true;\n    }\n};\n"
  },
  {
    "path": "docs/snippets/before_after.sh",
    "content": "php artisan operations --before\n\n# some commands\n\nphp artisan operations\n"
  },
  {
    "path": "docs/snippets/deployer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\ntask('deploy', [\n    // ...\n    'artisan:migrate',\n    'artisan:operation --before', // here\n    'deploy:publish',\n    'php-fpm:reload',\n    'artisan:queue:restart',\n    'artisan:operations', // here\n]);\n"
  },
  {
    "path": "docs/snippets/di_invoke.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Tests\\Concerns\\Some;\n\nreturn new class extends Operation {\n    public function __invoke(Some $some): void\n    {\n        $value = $some->get('qwerty');\n    }\n};\n"
  },
  {
    "path": "docs/snippets/di_up_down.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Tests\\Concerns\\Some;\n\nreturn new class extends Operation {\n    public function up(Some $some): void\n    {\n        $value = $some->get('qwerty');\n    }\n\n    public function down(Some $some): void\n    {\n        $value = $some->get('qwerty');\n    }\n};\n"
  },
  {
    "path": "docs/snippets/empty.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke(): void\n    {\n        // some code\n    }\n};\n"
  },
  {
    "path": "docs/snippets/event_service_provider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Providers;\n\nuse App\\Listeners\\SomeOperationsListener;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationEnded;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationFailed;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationStarted;\nuse DragonCode\\LaravelDeployOperations\\Events\\NoPendingDeployOperations;\nuse Illuminate\\Foundation\\Support\\Providers\\EventServiceProvider as ServiceProvider;\n\nclass EventServiceProvider extends ServiceProvider\n{\n    protected $listen = [\n        DeployOperationStarted::class    => [SomeOperationsListener::class],\n        DeployOperationEnded::class      => [SomeOperationsListener::class],\n        DeployOperationFailed::class     => [SomeOperationsListener::class],\n        NoPendingDeployOperations::class => [SomeOperationsListener::class],\n    ];\n}\n"
  },
  {
    "path": "docs/snippets/events_list.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nDragonCode\\LaravelDeployOperations\\Events\\DeployOperationStarted::class;\nDragonCode\\LaravelDeployOperations\\Events\\DeployOperationEnded::class;\nDragonCode\\LaravelDeployOperations\\Events\\DeployOperationFailed::class;\nDragonCode\\LaravelDeployOperations\\Events\\NoPendingDeployOperations::class;\n"
  },
  {
    "path": "docs/snippets/example.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse App\\Models\\Article;\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke(): void\n    {\n        Article::query()\n            ->lazyById(chunkSize: 100, column: 'id')\n            ->each->update(['is_active' => true]);\n        // and/or any actions...\n    }\n};\n"
  },
  {
    "path": "docs/snippets/example_artisan.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke(): void\n    {\n        $this->artisan('some_command', [\n            // parameters\n        ]);\n    }\n};\n"
  },
  {
    "path": "docs/snippets/except_environment.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke()\n    {\n        // some\n    }\n\n    public function shouldRun(): bool\n    {\n        return ! in_array(app()->environment(), ['testing', 'staging'], true);\n    }\n};\n"
  },
  {
    "path": "docs/snippets/failed_status.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Support\\Facade\\Log;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        throw new Exeption;\n    }\n\n    public function down(): void\n    {\n        throw new Exeption;\n    }\n\n    public function success(): void\n    {\n        Log::info('success');\n    }\n\n    public function failed(): void\n    {\n        Log::info('failed');\n    }\n};\n"
  },
  {
    "path": "docs/snippets/invokable_status.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Support\\Facade\\Log;\n\nreturn new class extends Operation {\n    public function __invoke(): void\n    {\n        // some\n    }\n\n    public function success(): void\n    {\n        Log::info('success');\n    }\n\n    public function failed(): void\n    {\n        Log::info('failed');\n    }\n};\n"
  },
  {
    "path": "docs/snippets/invoke_and_down.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    // called when `php artisan operations` running\n    public function __invoke(): void {}\n\n    // doesn't call when `php artisan migrate:rollback` running\n    // and any other commands to revert the operation.\n    public function down(): void {}\n};\n"
  },
  {
    "path": "docs/snippets/listen_events.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse App\\Listeners\\SomeOperationsListener;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationEnded;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationFailed;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationStarted;\nuse DragonCode\\LaravelDeployOperations\\Events\\NoPendingDeployOperations;\nuse Illuminate\\Support\\Facades\\Event;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    public function boot(): void\n    {\n        Event::listen([\n            DeployOperationStarted::class,\n            DeployOperationEnded::class,\n            DeployOperationFailed::class,\n            NoPendingDeployOperations::class,\n        ], SomeOperationsListener::class);\n    }\n}\n"
  },
  {
    "path": "docs/snippets/make_auto.sh",
    "content": "php artisan make:operation\n\n### When the git repository is found (`base_path('.git')` directory is exists) and HEAD branch name is 'qwerty'\n# 2022_10_11_225116_qwerty.php\n# 2022_10_11_225118_qwerty.php\n# 2022_10_11_225227_qwerty.php\n\n### When the git repository is not found (`base_path('.git')` directory doesn't exists).\n# 2022_10_11_225116_auto.php\n# 2022_10_11_225118_auto.php\n# 2022_10_11_225227_auto.php\n"
  },
  {
    "path": "docs/snippets/need_before.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke()\n    {\n        // some\n    }\n\n    public function needBefore(): bool\n    {\n        return false;\n    }\n};\n"
  },
  {
    "path": "docs/snippets/nested.sh",
    "content": "php artisan make:operation Foo/Bar/QweRty\nphp artisan make:operation Foo/Bar/QweRty.php\n\nphp artisan make:operation Foo\\Bar\\QweRty\nphp artisan make:operation Foo\\Bar\\QweRty.php\n\nphp artisan make:operation foo\\bar\\QweRty\nphp artisan make:operation foo\\bar\\QweRty.php\n"
  },
  {
    "path": "docs/snippets/nested_example.sh",
    "content": "php artisan make:operation foo\\bar\\QweRty\n# operations/foo/bar/2022_10_11_225734_qwe_rty.php\n\nphp artisan make:operation foo\\bar\\QweRty.php\n# operations/foo/bar/2022_10_11_225734_qwe_rty.php\n\nphp artisan make:operation foo/bar/QweRty\n# operations/foo/bar/2022_10_11_225734_qwe_rty.php\n\nphp artisan make:operation foo/bar/QweRty.php\n# operations/foo/bar/2022_10_11_225734_qwe_rty.php\n"
  },
  {
    "path": "docs/snippets/on_environment.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke()\n    {\n        // some\n    }\n\n    public function shouldRun(): bool\n    {\n        return app()->isProduction();\n    }\n};\n"
  },
  {
    "path": "docs/snippets/on_environments.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke()\n    {\n        // some\n    }\n\n    public function shouldRun(): bool\n    {\n        return in_array(app()->environment(), ['testing', 'staging'], true);\n    }\n};\n"
  },
  {
    "path": "docs/snippets/once_method.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke()\n    {\n        // some\n    }\n\n    public function shouldOnce(): bool\n    {\n        return false;\n    }\n};\n"
  },
  {
    "path": "docs/snippets/operation_helper_all.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Helpers\\OperationHelper;\n\nOperationHelper::run();\n"
  },
  {
    "path": "docs/snippets/operation_helper_directory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Helpers\\OperationHelper;\n\nOperationHelper::run('foo');\n\n// also you can use a real path\nOperationHelper::run(__DIR__ . '/../foo', realpath: true);\n"
  },
  {
    "path": "docs/snippets/operation_helper_file.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Helpers\\OperationHelper;\n\nOperationHelper::run('foo/2022_10_14_000002_test2');\n// or\nOperationHelper::run('foo/2022_10_14_000002_test2.php');\n\n// also you can use a real path\nOperationHelper::run(__DIR__ . '/../foo/2022_10_14_000002_test2', realpath: true);\n// or\nOperationHelper::run(__DIR__ . '/../foo/2022_10_14_000002_test2.php', realpath: true);\n"
  },
  {
    "path": "docs/snippets/operations_helper.sh",
    "content": "2022_10_14_000001_test1\nfoo/2022_10_14_000002_test2\nfoo/2022_10_14_000003_test3\nbar/2022_10_14_000004_test4\n2022_10_14_000004_test5\n"
  },
  {
    "path": "docs/snippets/operations_status.sh",
    "content": "2025_04_02_100000_some ............................................ [1] Ran\n2025_04_02_100001_some ............................................ [1] Ran\n2025_04_02_100002_some ............................................ [2] Ran\n2025_04_02_100003_some............................................. [3] Ran\n2025_04_02_100004_some............................................. [3] Ran\n2025_04_02_100005_some............................................. Pending\n2025_04_02_100006_some............................................. Pending\n"
  },
  {
    "path": "docs/snippets/order_running_operations.sh",
    "content": "# order of running operations at startup\n2022_10_14_000001_test1      # 1\nfoo/2022_10_14_000002_test2  # 2\nbar/2022_10_14_000003_test3  # 3\n2022_10_14_000004_test4      # 4\n"
  },
  {
    "path": "docs/snippets/rollback.sh",
    "content": "php artisan operations:rollback\n# operation                 batch\n# 2022_10_12_021837_some    1\n# 2022_10_12_021838_some    2\n# 2022_10_12_021839_some    2\n# 2022_10_12_021840_some    3  // will be canceled\n# 2022_10_12_021841_some    3  // will be canceled\n\nphp artisan operations:rollback --step=1\n# operation                 batch\n# 2022_10_12_021837_some    1\n# 2022_10_12_021838_some    2\n# 2022_10_12_021839_some    2\n# 2022_10_12_021840_some    3  // will be canceled\n# 2022_10_12_021841_some    3  // will be canceled\n\nphp artisan operations:rollback --step=2\n# operation                 batch\n# 2022_10_12_021837_some    1\n# 2022_10_12_021838_some    2  // will be canceled\n# 2022_10_12_021839_some    2  // will be canceled\n# 2022_10_12_021840_some    3  // will be canceled\n# 2022_10_12_021841_some    3  // will be canceled\n"
  },
  {
    "path": "docs/snippets/some_listener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listeners;\n\nuse DragonCode\\LaravelDeployOperations\\Events\\BaseEvent;\n\nclass SomeOperationsListener\n{\n    public function handle(BaseEvent $event): void\n    {\n        $method   = $event->method; // MethodEnum object value\n        $isBefore = $event->before; // boolean\n    }\n}\n"
  },
  {
    "path": "docs/snippets/success_status.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Support\\Facade\\Log;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        // some\n    }\n\n    public function down(): void\n    {\n        // some\n    }\n\n    public function success(): void\n    {\n        Log::info('success');\n    }\n\n    public function failed(): void\n    {\n        Log::info('failed');\n    }\n};\n"
  },
  {
    "path": "docs/snippets/with_operation.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\n\nreturn new class extends Migration {\n    public function __invoke()\n    {\n        // some\n    }\n\n    public function withOperation(): string\n    {\n        return 'foo/2022_10_14_000002_test2';\n    }\n};\n"
  },
  {
    "path": "docs/snippets/with_operation_helper.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\n\nuse function DragonCode\\LaravelDeployOperations\\operation;\n\nreturn new class extends Migration {\n    public function withOperation(): string\n    {\n        return operation('foo/2022_10_14_000002_test2');\n    }\n};\n"
  },
  {
    "path": "docs/snippets/within_transactions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke()\n    {\n        // some\n    }\n\n    public function withinTransactions(): bool\n    {\n        return true;\n    }\n};\n"
  },
  {
    "path": "docs/topics/artisan-commands.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Artisan Commands\" id=\"artisan-commands\">\n\n    <link-summary>Information on how to call Artisan commands from operations</link-summary>\n    <card-summary>Information on how to call Artisan commands from operations</card-summary>\n    <web-summary>Information on how to call Artisan commands from operations</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <p>\n        Quite often, when working with operations, it becomes necessary to run one or another console command, and each time you have to write the following code:\n    </p>\n\n    <code-block lang=\"php\" src=\"example_artisan.php\" include-lines=\"5-\" />\n</topic>\n"
  },
  {
    "path": "docs/topics/creating-operations.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Creating Operations\" id=\"creating-operations\" help-id=\"creating-operations\">\n\n    <link-summary>Information on how to create operations</link-summary>\n    <card-summary>Information on how to create operations</card-summary>\n    <web-summary>Information on how to create operations</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <snippet id=\"creating\">\n        <p>\n            To create an operation use the <code>%command_make%</code> artisan command:\n        </p>\n\n        <code-block lang=\"bash\">\n        %artisan% %command_make% some_name\n    </code-block>\n\n        <p>\n            The new operation's file will be placed in your\n            <code>%directory%</code> directory in the base path of your app.\n        </p>\n\n        <p>\n            Each operation file name contains a timestamp, which allows Laravel to determine the order of the operations.\n            For example,\n        </p>\n\n        <code-block lang=\"bash\">\n            2025_04_02_121627_some_name.php\n        </code-block>\n    </snippet>\n\n    <chapter title=\"Asks For File Name\" id=\"asks_for_file_name\">\n        <tip>\n            The question will not be asked when calling a console command passing the <code>--quiet</code> parameter.\n        </tip>\n\n        <p>\n            When calling the <code>%command_run%</code> console command without passing a name in the name parameter,\n            you will be asked for a <code>name</code> for the file.\n        </p>\n\n        <code-block lang=\"bash\" src=\"ask.sh\" />\n\n        <p>\n            You can enter your own or simply press <code>Enter</code> to continue.\n            In this case, automatic file name generation will be applied\n        </p>\n    </chapter>\n\n    <chapter title=\"Automatically Generate A File Name\" id=\"automatically_generate_a_file_name\">\n        <p>\n            If you do not specify the <code>name</code> attribute,\n            then the file name will be generated automatically according to the rule:\n        </p>\n\n        <code-block lang=\"bash\" src=\"make_auto.sh\" />\n\n        <tip>\n            <p>\n                The name for the file will be automatically obtained from the currently active git repository branch at the root of the project.\n            </p>\n            <p>\n                If the branch name cannot be determined, the word “auto” will be used.\n            </p>\n        </tip>\n    </chapter>\n\n    <chapter title=\"Nested Files\" id=\"nested_files\">\n        <p>\n            You can use nested paths to create operations:\n        </p>\n\n        <code-block lang=\"bash\" src=\"nested.sh\" />\n\n        <p>\n            All of these commands will create a file called <code>%directory%/foo/bar/Y_m_d_His_qwe_rty.php.</code>\n        </p>\n\n        <p>\n            For example:\n        </p>\n\n        <code-block lang=\"bash\" src=\"nested_example.sh\" />\n    </chapter>\n\n    <chapter title=\"Invokable Method\" id=\"invokable_method\">\n        <p>\n            By default, the new operation class will contain the <code>__invoke</code> method,\n            but you can easily replace it with public <code>up</code> name.\n        </p>\n\n        <code-block lang=\"php\" src=\"empty.php\" include-lines=\"5-\" />\n\n        <note>\n            <p>\n                Note that the <code>__invoke</code> method has been added as a single call.\n                This means that when the operation is running, it will be called, but not when it is rolled back.\n            </p>\n\n            <p>\n                You should also pay attention to the fact that if there is an <code>__invoke</code> method in the class,\n                the <code>down</code> method will not be called.\n            </p>\n        </note>\n\n        <code-block lang=\"php\" src=\"invoke_and_down.php\" include-lines=\"5-\" />\n    </chapter>\n\n    <chapter title=\"Dependency Injection\" id=\"dependency_injection\">\n        <p>\n            You can also use the dependency injection with <code>__invoke</code>, <code>up</code> and\n            <code>down</code> methods:\n        </p>\n\n        <code-block lang=\"php\" src=\"di_invoke.php\" include-lines=\"5-\" />\n        <code-block lang=\"php\" src=\"di_up_down.php\" include-lines=\"5-\" />\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/customize-stub.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Customize Stub\" id=\"customize-stub\">\n\n    <link-summary>Information on how to publish a template file for changes</link-summary>\n    <card-summary>Information on how to publish a template file for changes</card-summary>\n    <web-summary>Information on how to publish a template file for changes</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <p>\n        You may publish the stub used by the <code>make:operation</code> command and/or\n        <a href=\"https://laravel-idea.com\">Laravel Idea</a> plugin for\n        <a href=\"https://www.jetbrains.com/phpstorm/\">JetBrains PhpStorm</a> if you want to modify it.\n    </p>\n\n    <code-block lang=\"bash\">\n        %vendor_publish%\n    </code-block>\n\n    <p>\n        This will create the file <code>stubs/deploy-operation.stub</code>, which you can modify to suit you.\n\n    </p>\n\n    <code-block\n        lang=\"php\"\n        src=\"https://raw.githubusercontent.com/TheDragonCode/laravel-deploy-operations/refs/heads/main/resources/stubs/deploy-operation.stub\"\n    />\n</topic>\n"
  },
  {
    "path": "docs/topics/database-data-dumper.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Database Data Dumper\" id=\"database-data-dumper\">\n\n    <link-summary>Adding data from certain tables when executing the `php artisan schema:dump` console command</link-summary>\n    <card-summary>Adding data from certain tables when executing the `php artisan schema:dump` console command</card-summary>\n    <web-summary>Adding data from certain tables when executing the `php artisan schema:dump` console command</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <p>\n        As you build your application, you may accumulate more and more migrations over time.\n        This can lead to your\n        <code>database/migrations</code> directory becoming bloated with potentially hundreds of migrations.\n        If you would like, you may \"squash\" your migrations into a single SQL file.\n        To get started, execute the <code>schema:dump</code> command:\n    </p>\n\n    <code-block lang=\"bash\">\n        %artisan% schema:dump\n    </code-block>\n\n    <p>\n        You can read more about the operation of this console command in the\n        <a href=\"https://laravel.com/docs/migrations#squashing-migrations\">Laravel documentation</a>.\n    </p>\n\n    <p>\n        Here we mention this console command because operations tend to save the execution state in order to prevent re-runs where this is not explicitly allowed.\n        But if you run sequentially the console commands <code>%artisan% schema:dump</code> and\n        <code>%artisan% migrate:fresh</code>, you will see that all actions will be called again.\n    </p>\n\n    <p>\n        This is due to the fact that the dump mechanism saves the contents of just one table - <code>migrations</code>.\n    </p>\n\n    <p>\n        To solve this problem, there is a\n        <a href=\"https://github.com/TheDragonCode/laravel-data-dumper\">Database Data Dumper</a>\n        project that allows you to specify a list of tables required for export to a dump.\n    </p>\n\n    <p>\n        In addition to those that you can easily specify in its configuration file,\n        we recommend that you also specify the\n        <code>operations</code> database table from this project in order to save the state of the operations when performing a clean deployment of the database from a dump.\n    </p>\n\n    <code-block lang=\"bash\">\n        composer require dragon-code/laravel-data-dumper --dev\n    </code-block>\n</topic>\n"
  },
  {
    "path": "docs/topics/events.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Events\" id=\"events\">\n\n    <link-summary>Information about events sent when operations are running</link-summary>\n    <card-summary>Information about events sent when operations are running</card-summary>\n    <web-summary>Information about events sent when operations are running</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <p>\n        You can also handle events when executing operations:\n    </p>\n\n    <code-block lang=\"php\" src=\"events_list.php\" include-lines=\"5-\" />\n\n    <p>\n        If there are no operation files to execute, the <code>NoPendingDeployOperations</code> event will be sent.\n    </p>\n\n    <p>\n        In other cases, the <code>DeployOperationStarted</code> event will be sent before processing starts,\n        and the <code>DeployOperationEnded</code> event will be sent after processing.\n    </p>\n\n    <p>\n        For example:\n    </p>\n\n\n    <code-block lang=\"php\" src=\"event_service_provider.php\" include-lines=\"5-\" />\n    <code-block lang=\"php\" src=\"some_listener.php\" include-lines=\"5-\" />\n\n    <p>\n        It is also possible to subscribe to events manually:\n    </p>\n\n    <code-block lang=\"php\" src=\"listen_events.php\" include-lines=\"5-\" />\n</topic>\n"
  },
  {
    "path": "docs/topics/execution-status.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Execution Status\" id=\"execution-status\">\n\n    <link-summary>Information about the execution of actions during successful and unsuccessful operation launches</link-summary>\n    <card-summary>Information about the execution of actions during successful and unsuccessful operation launches</card-summary>\n    <web-summary>Information about the execution of actions during successful and unsuccessful operation launches</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <p>\n        You can also override the <code>success</code> and <code>failed</code> methods,\n        which are called on success or failure processing.\n    </p>\n\n    <chapter title=\"Success\" id=\"success\">\n        <code-block lang=\"php\" src=\"success_status.php\" include-lines=\"5-\" />\n\n        <p>\n            Call the <code>%artisan% %command_run%</code> command.\n        </p>\n\n        <p>\n            The log file will contain one <code>success</code> record.\n        </p>\n    </chapter>\n\n    <chapter title=\"Failed\" id=\"failed\">\n        <code-block lang=\"php\" src=\"failed_status.php\" include-lines=\"5-\" />\n\n        <p>\n            Call the <code>%artisan% %command_run%</code> command.\n        </p>\n\n        <p>\n            The log file will contain one <code>failed</code> record.\n        </p>\n    </chapter>\n\n    <chapter title=\"Invokable\" id=\"invokable\">\n        <p>\n            The methods will work in the same way in conjunction with the <code>__invoke</code> magic method.\n            The only difference is that in this case the down method will not be executed.\n        </p>\n\n        <code-block lang=\"php\" src=\"invokable_status.php\" include-lines=\"5-\" />\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/installation.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Installation\" id=\"installation\">\n\n    <link-summary>Installation and configuration</link-summary>\n    <card-summary>Installation and configuration</card-summary>\n    <web-summary>Installation and configuration</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <p>\n        To get the latest version of\n        <format style=\"bold\">%product_short%</format>\n        , simply require the project using\n        <a href=\"https://getcomposer.org\">Composer</a>:\n    </p>\n\n    <code-block lang=\"bash\">\n    composer require %package_name%\n    </code-block>\n\n    <p>\n        If necessary, you can publish the configuration file by calling the console command:\n    </p>\n\n    <code-block lang=\"bash\">\n        %vendor_publish%\n    </code-block>\n\n    <p>\n        Now you can\n        <a href=\"creating-operations.topic\">\n            <format style=\"bold\">create</format>\n        </a>\n        new operations.\n    </p>\n\n    <chapter title=\"Compatibility Table\" id=\"compatibility_table\">\n        <table>\n            <tr>\n                <td>PHP</td>\n                <td>Laravel</td>\n                <td>Package</td>\n                <td>Documentation</td>\n                <td>Status</td>\n            </tr>\n            <tr>\n                <td>^8.2</td>\n                <td>11, 12, 13</td>\n                <td>^7.0</td>\n                <td><a href=\"introduction.topic\" /></td>\n                <td><img src=\"%badge_supported%\" alt=\"supported\" /></td>\n            </tr>\n            <tr>\n                <td>^8.2</td>\n                <td>10, 11, 12</td>\n                <td>^6.0</td>\n                <td><a href=\"https://github.com/TheDragonCode/laravel-deploy-operations/tree/6.x/docs\">Documentation</a>\n                </td>\n                <td><img src=\"%badge_not_supported%\" alt=\"not supported\" /></td>\n            </tr>\n            <tr>\n                <td>^8.2</td>\n                <td>10, 11</td>\n                <td>^5.0</td>\n                <td><a href=\"https://github.com/TheDragonCode/laravel-deploy-operations/tree/5.x/docs\">Documentation</a>\n                </td>\n                <td><img src=\"%badge_not_supported%\" alt=\"not supported\" /></td>\n            </tr>\n            <tr>\n                <td>^8.0</td>\n                <td>7, 8, 9, 10, 11</td>\n                <td>^4.0</td>\n                <td><a href=\"https://github.com/TheDragonCode/laravel-deploy-operations/tree/4.x/docs\">Documentation</a>\n                </td>\n                <td><img src=\"%badge_not_supported%\" alt=\"not supported\" /></td>\n            </tr>\n            <tr>\n                <td>^8.0</td>\n                <td>7, 8, 9</td>\n                <td>^3.0</td>\n                <td><a href=\"https://github.com/TheDragonCode/laravel-deploy-operations/tree/3.x/docs\">Documentation</a>\n                </td>\n                <td><img src=\"%badge_not_supported%\" alt=\"not supported\" /></td>\n            </tr>\n            <tr>\n                <td>^7.3, ^8.0</td>\n                <td>6, 7, 8, 9</td>\n                <td>^2.0</td>\n                <td>---</td>\n                <td><img src=\"%badge_not_supported%\" alt=\"not supported\" /></td>\n            </tr>\n            <tr>\n                <td>^7.3, ^8.0</td>\n                <td>6, 7, 8</td>\n                <td>^1.0</td>\n                <td>---</td>\n                <td><img src=\"%badge_not_supported%\" alt=\"not supported\" /></td>\n            </tr>\n        </table>\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/introduction.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Introduction\" id=\"introduction\">\n\n    <section-starting-page>\n        <title>%product%</title>\n\n        <description>\n            ⚡ Performing any actions during the deployment process\n        </description>\n\n        <spotlight>\n            <a href=\"installation.topic\" type=\"development\" />\n            <a href=\"usage.topic\" type=\"integration\" />\n        </spotlight>\n\n        <primary>\n            <title>Guide</title>\n\n            <a href=\"running-operations.topic\" type=\"start\" />\n            <a href=\"creating-operations.topic\" type=\"tools\" />\n            <a href=\"rolling-back-operations.topic\" type=\"turn-on\" />\n            <a href=\"operations-status.topic\" type=\"check-list\" />\n        </primary>\n\n        <secondary>\n            <title>Helpers</title>\n\n            <a href=\"artisan-commands.topic\" />\n            <a href=\"events.topic\" />\n            <a href=\"execution-status.topic\" />\n        </secondary>\n\n        <misc>\n            <cards>\n                <title>Extras</title>\n\n                <a href=\"database-data-dumper.topic\" />\n            </cards>\n        </misc>\n    </section-starting-page>\n</topic>\n"
  },
  {
    "path": "docs/topics/operation-helper.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Operation Helper\" id=\"operation-helper\">\n\n    <link-summary>Information about launching operations with the help of the helper</link-summary>\n    <card-summary>Information about launching operations with the help of the helper</card-summary>\n    <web-summary>Information about launching operations with the help of the helper</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <p>\n        To quickly call operations from other code, you can use the <code>OperationHelper</code> helper function.\n    </p>\n\n    <chapter title=\"Execution of all\" id=\"execution_of_all\">\n        <p>\n            This will execute any operations not performed earlier:\n        </p>\n\n        <code-block lang=\"php\" src=\"operation_helper_all.php\" include-lines=\"5-\" />\n\n        <p>\n            For example,\n        </p>\n\n        <code-block lang=\"bash\" src=\"operations_helper.sh\" />\n    </chapter>\n\n    <chapter title=\"Performing operations in a folder\" id=\"performing_operations_in_a_folder\">\n        <p>\n            This will execute all previously unexecuted operations in the specified folder:\n        </p>\n\n        <code-block lang=\"php\" src=\"operation_helper_directory.php\" include-lines=\"5-\" />\n\n        <p>\n            For example,\n        </p>\n\n        <code-block lang=\"bash\" src=\"operations_helper.sh\" include-lines=\"2-3\" />\n    </chapter>\n\n    <chapter title=\"Performing a specific operation\" id=\"performing_a_specific_operation\">\n        <warning>\n            This will execute the defined operation file even if it was previously called.\n            Be careful about calling it again.\n        </warning>\n\n        <code-block lang=\"php\" src=\"operation_helper_file.php\" include-lines=\"5-\" />\n\n        <p>\n            For example,\n        </p>\n\n        <code-block lang=\"bash\" src=\"operations_helper.sh\" include-lines=\"2\" />\n    </chapter>\n\n    <chapter title=\"Laravel Idea support\" id=\"laravel_idea_support\">\n        <p>\n            If you are using\n            <a href=\"https://www.jetbrains.com/phpstorm/\">JetBrains PhpStorm</a>\n            with the\n            <a href=\"https://laravel-idea.com\">Laravel Idea</a> plugin installed,\n            you can use the <code>operation</code> function to autocomplete.\n        </p>\n\n        <img src=\"operation_helper_class.png\" alt=\"operation helper\" />\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/operations-status.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Operations Status\" id=\"operations-status\">\n\n    <link-summary>Information on how to view the status of performed operations</link-summary>\n    <card-summary>Information on how to view the status of performed operations</card-summary>\n    <web-summary>Information on how to view the status of performed operations</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <p>\n        The <code>%command_status%</code> command displays the execution status of operations.\n        In it you can see which operations were executed and which were not:\n    </p>\n\n    <code-block lang=\"bash\">\n        %artisan% %command_status%\n    </code-block>\n\n    <p>\n        For example,\n    </p>\n\n    <code-block lang=\"bash\" src=\"operations_status.sh\" />\n</topic>\n"
  },
  {
    "path": "docs/topics/rolling-back-operations.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Rolling Back Operations\" id=\"rolling-back-operations\">\n\n    <link-summary>Information on how to roll back operations</link-summary>\n    <card-summary>Information on how to roll back operations</card-summary>\n    <web-summary>Information on how to roll back operations</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <p>\n        To roll back the latest operation, you may use the <code>%command_rollback%</code> command.\n        This command rolls back the last \"batch\" of operations, which may include multiple operation files:\n    </p>\n\n    <code-block lang=\"bash\">\n        %artisan% %command_rollback%\n    </code-block>\n\n    <p>\n        You may roll back a limited number of operations by providing the\n        <code>step</code> option to the rollback command.\n        For example, the following command will roll back the last five operations:\n    </p>\n\n    <code-block lang=\"bash\">\n        %artisan% %command_rollback% --step=5\n    </code-block>\n\n    <p>\n        For example:\n    </p>\n\n    <code-block lang=\"bash\" src=\"rollback.sh\" />\n\n    <chapter title=\"Drop All &amp; Rerun Operations\" id=\"drop_all_amp_rerun_operations\">\n        <p>\n            The\n            <code>%command_fresh%</code> command will drop all operation records from the operation table and then execute the operations command:\n        </p>\n\n        <code-block lang=\"bash\">\n            %artisan% %command_fresh%\n        </code-block>\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/running-operations.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Running Operations\" id=\"running-operations\">\n\n    <link-summary>Information on how to invoke operations during a deployment</link-summary>\n    <card-summary>Information on how to invoke operations during a deployment</card-summary>\n    <web-summary>Information on how to invoke operations during a deployment</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <snippet id=\"run_all\">\n\n        <p>\n            To run all of your outstanding operations, execute the <code>%command_run%</code> artisan command:\n        </p>\n\n        <code-block lang=\"bash\">\n            %artisan% %command_run%\n        </code-block>\n\n        <p>\n            The order in which operations are called is checked by file name in alphabetical order, without taking into account directory names:\n        </p>\n\n        <code-block lang=\"bash\" src=\"actual_file_names.sh\" />\n        <code-block lang=\"bash\" src=\"order_running_operations.sh\" />\n    </snippet>\n\n    <chapter title=\"Isolating Execution\" id=\"isolating_execution\">\n        <p>\n            If you are deploying your application across multiple servers and running operations as part of your deployment process,\n            you likely do not want two servers attempting to run the database at the same time.\n            To avoid this, you may use the <code>isolated</code> option when invoking the\n            <code>%command_run%</code> command.\n        </p>\n\n        <code-block lang=\"bash\">\n            %artisan% %command_run% --isolated\n        </code-block>\n    </chapter>\n\n    <chapter title=\"Split Execution\" id=\"split_execution\">\n        <p>\n            Sometimes it becomes necessary to launch operations separately, for example, to notify about the successful deployment of a project.\n        </p>\n\n        <p>\n            There is a <code>before</code> option for this when calling operations:\n        </p>\n\n        <code-block lang=\"bash\">\n            %artisan% %command_run% --before\n        </code-block>\n\n        <p>\n            When you call the <code>%command_run%</code> command with the <code>before</code> parameter,\n            the script will only perform operations for which the <code>needBefore</code> method is <code>true</code>.\n        </p>\n\n        <p>\n            For backwards compatibility, the <code>needBefore</code> method returns <code>true</code> by default,\n            but operations will only be executed if the option is explicitly passed.\n        </p>\n\n        <code-block lang=\"php\" src=\"need_before.php\" include-lines=\"5-\" />\n\n        <p>\n            For example, you need to call operations when deploying an application. Some operations should be run after the operations are deployed, and others after the application is fully launched.\n        </p>\n\n        <p>\n            To run, you need to pass the <code>before</code> parameter.\n            For example, when using\n            <a href=\"https://github.com/deployphp/deployer\">Deployer</a> it would look like this:\n        </p>\n\n        <code-block lang=\"php\" src=\"deployer.php\" include-lines=\"5-\" />\n\n        <p>\n            Thus, when <code>%command_run%</code> is called, all operations whose\n            <code>before</code> parameter is <code>true</code> will be executed,\n            and after that, the remaining tasks will be executed.\n        </p>\n\n        <note>\n            If you call the <code>%command_run%</code> command without the <code>before</code> parameter,\n            then all tasks will be executed regardless of the value of the\n            <code>needBefore</code> method inside the operation class.\n        </note>\n    </chapter>\n\n    <chapter title=\"Forcing Operations\" id=\"forcing_operations\">\n        <tip>\n            Some commands cannot be executed in production without confirmation.\n            These include all commands except <code>%command_status%</code> and <code>%command_run%</code>.\n        </tip>\n\n        <p>\n            Some operations are destructive, which means they may cause you to lose data.\n            In order to protect you from running these commands against your production database,\n            you will be prompted for confirmation before the commands are executed.\n            To force the commands to run without a prompt, use the <code>--force</code> flag:\n        </p>\n\n        <code-block lang=\"bash\">\n            %artisan% %command_install% --force\n        </code-block>\n    </chapter>\n\n    <chapter title=\"Every Time\" id=\"every_time\">\n        <p>\n            In some cases, you need to call the code every time you deploy the application. For example, to call reindexing.\n        </p>\n\n        <p>\n            To do this, override the <code>shouldOnce</code> method in the operation file:\n        </p>\n\n        <code-block lang=\"php\" src=\"once_method.php\" include-lines=\"5-\" />\n\n        <p>\n            If the value is <code>shouldOnce</code> is <code>false</code>,\n            the up method will be called every time the <code>%command_run%</code> command called.\n        </p>\n\n        <p>\n            In this case, information about it will not be written to the\n            <code>%table%</code> table and, therefore, the\n            <code>down</code> method will not be called when the rollback command is called.\n        </p>\n\n        <note>\n            When using the <code>before</code> parameter to run command,\n            it is recommended to override the value of the <code>needBefore</code> method to <code>false</code>,\n            otherwise this operation will be executed twice.\n        </note>\n    </chapter>\n\n    <chapter title=\"Specific Environment\" id=\"specific_environment\">\n        <note>\n            By default, the operation will run in all environments.\n        </note>\n\n        <p>\n            In some cases, it becomes necessary to execute an operation in a specific environment.\n            For example <code>production</code>.\n        </p>\n\n        <p>\n            For this you can override the <code>shouldRun</code> method:\n        </p>\n\n        <code-block lang=\"php\" src=\"on_environment.php\" include-lines=\"5-\" />\n\n        <p>\n            You can also specify multiple environment names:\n        </p>\n\n        <code-block lang=\"php\" src=\"on_environments.php\" include-lines=\"5-\" />\n\n        <p>\n            You can work with exceptions in the same way:\n        </p>\n\n        <code-block lang=\"php\" src=\"except_environment.php\" include-lines=\"5-\" />\n    </chapter>\n\n    <chapter title=\"Database Transactions\" id=\"database_transactions\">\n        <p>\n            In some cases, it becomes necessary to undo previously performed operations in the database.\n            For example, when code execution throws an error. To do this, the code must be wrapped in a transaction.\n        </p>\n\n        <p>\n            By setting the <code>withinTransactions</code> to <code>true</code> parameter,\n            you will ensure that your code is wrapped in a transaction without having to manually call the\n            <code>DB::transaction()</code> method.\n            This will reduce the time it takes to create the operation.\n        </p>\n\n        <code-block lang=\"php\" src=\"within_transactions.php\" include-lines=\"5-\" />\n\n        <tip>\n            <p>\n                The number of code execution attempts in case of transaction errors is set in the\n                <a href=\"%config_url%\">settings</a> file.\n            </p>\n            <p>\n                By default, the number of attempts is %transactions_attempts%.\n            </p>\n        </tip>\n    </chapter>\n\n    <chapter title=\"Asynchronous Call\" id=\"asynchronous_call\">\n        <p>\n            In some cases, it becomes necessary to execute operations in an asynchronous manner without delaying the deployment process.\n        </p>\n\n        <p>\n            To do this, you need to override the <code>shouldBeAsync</code> method in the operation class:\n        </p>\n\n        <code-block lang=\"php\" src=\"async.php\" include-lines=\"5-\" />\n\n        <p>\n            In this case, the operation file that defines this parameter will run asynchronously using the\n            <code>DragonCode\\LaravelDeployOperations\\Jobs\\OperationJob</code> job.\n        </p>\n\n        <p>\n            The name of the connection and queue can be changed through the <a href=\"%config_url%\">settings</a>.\n        </p>\n\n        <note>\n            We remind you that in this case the\n            <a href=\"https://laravel.com/docs/queues\">queuing system</a> must work in your application.\n        </note>\n    </chapter>\n\n    <chapter title=\"Interaction with migrations\" id=\"interaction_with_migrations\">\n        <p>\n            Operations can also be invoked when Laravel migrations are completed (<code>php artisan migrate</code>).\n            The Laravel event system is used for this purpose.\n        </p>\n\n        <p>\n            To do this, add a <code>withOperation</code> public method to your migration file that\n            will return the name of the file or folder to call.\n            For example:\n        </p>\n\n        <code-block lang=\"php\" src=\"with_operation.php\" include-lines=\"5-\" />\n\n        <p>\n            Now, once the migration is done, Laravel will send a <code>MigrationEnded</code> event, catching which the\n            <code>%artisan% %command_run%</code> console command will be called passing this parameter.\n        </p>\n\n        <p>\n            The same thing will happen if you invoke the following console command:\n        </p>\n\n        <code-block lang=\"bash\">\n            %artisan% %command_run% --path=\"foo/2022_10_14_000002_test2\"\n        </code-block>\n\n        <p>\n            This method works with all three migration methods: <code>up</code>, <code>down</code> and\n            <code>__invoke</code>.\n        </p>\n\n        <p>\n            When the <code>%artisan% migrate</code> console command is called,\n            the operation will call the <code>up</code> or <code>__invoke</code> method.\n        </p>\n\n        <p>\n            When the <code>%artisan% migrate:rollback</code> console command is called,\n            the operation will call the <code>down</code> method if it exists in the operation file.\n        </p>\n\n        <chapter title=\"Laravel Idea support\" id=\"laravel_idea_support\">\n            <p>\n                If you are using\n                <a href=\"https://www.jetbrains.com/phpstorm/\">JetBrains PhpStorm</a>\n                with the\n                <a href=\"https://laravel-idea.com\">Laravel Idea</a> plugin installed,\n                then autocomplete will be available to you:\n            </p>\n            <p>\n                To avoid entering file names manually, you can use the <code>operation</code> helper function.\n                All it does is to suggest IDE paths to operation files with recursive search.\n            </p>\n\n            <code-block lang=\"php\" src=\"with_operation_helper.php\" include-lines=\"7-\" />\n\n            <img src=\"operations_helper_function.png\" alt=\"operation helper\"/>\n        </chapter>\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/snippets_composer.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic SYSTEM \"https://resources.jetbrains.com/writerside/1.0/html-entities.dtd\">\n<topic\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    is-library=\"true\"\n    id=\"snippets_composer\"\n    title=\"snippets composer\">\n\n    <snippet id=\"update\">\n        <p>\n            Then you need to update the dependencies:\n        </p>\n\n        <code-block lang=\"bash\">\n            composer update\n        </code-block>\n    </snippet>\n</topic>\n"
  },
  {
    "path": "docs/topics/upgrade-3.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Upgrading To 3.x from 2.x\" id=\"upgrade-3\">\n\n    <link-summary>Guide for upgrading to version 3.x from 2.x</link-summary>\n    <card-summary>Guide for upgrading to version 3.x from 2.x</card-summary>\n    <web-summary>Guide for upgrading to version 3.x from 2.x</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <procedure title=\"High-Impact Changes\" id=\"high_impact_changes\">\n        <step><a href=\"#updating_dependencies\" /></step>\n        <step><a href=\"#configuration\" /></step>\n        <step><a href=\"#anonymous_classes\" /></step>\n        <step><a href=\"#parent_namespace\" /></step>\n        <step><a href=\"#changed_properties\" /></step>\n        <step><a href=\"#added_recursive_search_for_actions_in_a_folder\" /></step>\n        <step><a href=\"#php_8_0_2_required\" /></step>\n        <step>Laravel 6.0 support was ended</step>\n        <step>Dragon Code: Contracts (<code>dragon-code/contracts</code>) support was ended</step>\n    </procedure>\n\n    <procedure title=\"Minor-Impact Changes\" id=\"minor_impact_changes\">\n        <step><a href=\"#changed_action_repository\" /></step>\n        <step><a href=\"#actions_location\" /></step>\n    </procedure>\n\n    <chapter title=\"The easiest way to upgrade\" id=\"the_easiest_way_to_upgrade\">\n        <note>\n            If you used inheritance of actions from other actions, then you will need to process these files manually.\n        </note>\n\n        <p>\n            For your convenience, we have created an upgrade console command:\n        </p>\n\n        <code-block lang=\"bash\">\n            composer require dragon-code/laravel-migration-actions:^3.0\n            %artisan% migrate:actions:upgrade\n            %artisan% migrate\n        </code-block>\n\n        <p>\n            It will do the following:\n        </p>\n\n        <list>\n            <li>Change the namespace of the abstract class</li>\n            <li>Add a strict type declaration</li>\n            <li>Replace the <code>up</code> method with <code>__invoke</code> if the class does not have a\n                <code>down</code> method\n            </li>\n            <li>Replace named classes with anonymous ones</li>\n            <li>Create a configuration file according to the data saved in your project</li>\n            <li>Changes properties from <code>snake_case</code> to <code>camelCase</code></li>\n        </list>\n    </chapter>\n\n    <chapter title=\"Updating Dependencies\" id=\"updating_dependencies\">\n        <chapter title=\"PHP 8.0.2 Required\" id=\"php_8_0_2_required\">\n            <p>\n                Deploy Actions for Laravel now requires PHP 8.0.2 or greater.\n            </p>\n        </chapter>\n\n        <chapter title=\"Composer Dependencies\" id=\"composer_dependencies\">\n            <p>\n                You should update the following dependency in your application's <code>composer.json</code> file:\n            </p>\n\n            <code-block lang=\"json\">\n                {\n                    \"require\": {\n                        \"dragon-code/laravel-migration-actions\": \"^3.0\"\n                    }\n                }\n            </code-block>\n        </chapter>\n    </chapter>\n\n    <chapter title=\"Configuration\" id=\"configuration\">\n        <p>\n            Publish the config file and migrate the settings from the <code>config/database.php</code> file to\n            <code>config/actions.php</code>.\n        </p>\n\n        <code-block lang=\"bash\">\n            %artisan% vendor:publish --provider=\"DragonCode\\LaravelActions\\ServiceProvider\"\n        </code-block>\n    </chapter>\n\n    <chapter title=\"Actions Location\" id=\"actions_location\">\n        Move the action files to the <code>actions</code> folder in the project root,\n        or update the <code>actions.path</code> option in the configuration file.\n    </chapter>\n\n    <chapter title=\"Parent Namespace\" id=\"parent_namespace\">\n        Replace <code>DragonCode\\LaravelActions\\Support\\Actionable</code> with\n        <code>DragonCode\\LaravelActions\\Action</code>.\n    </chapter>\n\n    <chapter title=\"Anonymous Classes\" id=\"anonymous_classes\">\n        <p>\n            Replace named calls to your application's classes with anonymous ones.\n        </p>\n\n        <p>\n            For example:\n        </p>\n\n        <code-block lang=\"php\">\n            // before\n            use DragonCode\\LaravelActions\\Support\\Actionable;\n\n            class Some extends Actionable { }\n\n            // after\n            use DragonCode\\LaravelActions\\Action;\n\n            return new class extends Action { };\n        </code-block>\n    </chapter>\n\n    <chapter title=\"Invokable Method\" id=\"invokable_method\">\n        If your class does not contain a <code>down</code> method, then you can replace the <code>up</code> method with\n        <code>__invoke</code>.\n    </chapter>\n\n    <chapter title=\"Changed Action Repository\" id=\"changed_action_repository\">\n        Just call the <code>%artisan% migrate</code> command to make changes to the action repository table.\n    </chapter>\n\n    <chapter title=\"Changed Properties\" id=\"changed_properties\">\n        <p>\n            Make sure all overridden properties are typed:\n        </p>\n\n        <table>\n            <tr>\n                <td>New Name</td>\n                <td>Old Name</td>\n            </tr>\n            <tr>\n                <td>protected bool $once</td>\n                <td>protected $once</td>\n            </tr>\n            <tr>\n                <td>protected bool $transactions</td>\n                <td>protected $transactions</td>\n            </tr>\n            <tr>\n                <td>protected int $transactionAttempts</td>\n                <td>protected $transaction_attempts</td>\n            </tr>\n            <tr>\n                <td>protected string\\|array\\|null $environment</td>\n                <td>protected $environment</td>\n            </tr>\n            <tr>\n                <td>protected string\\|array\\|null $exceptEnvironment</td>\n                <td>protected $except_environment</td>\n            </tr>\n            <tr>\n                <td>protected bool $before</td>\n                <td>protected $before</td>\n            </tr>\n        </table>\n    </chapter>\n\n    <chapter title=\"Added recursive search for actions in a folder\" id=\"added_recursive_search_for_actions_in_a_folder\">\n        <p>\n            Before:\n        </p>\n\n        <code-block lang=\"bash\">\n            2022_10_13_013321_test1\n            2022_10_13_013326_test2\n            bar/2022_10_13_013323_test3 # will not be called\n        </code-block>\n\n        <p>\n            After:\n        </p>\n\n        <code-block lang=\"bash\">\n            2022_10_13_013321_test1\n            2022_10_13_013326_test2\n            bar/2022_10_13_013323_test3 # will be called\n        </code-block>\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/upgrade-4.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Upgrading To 4.x from 3.x\" id=\"upgrade-4\">\n\n    <link-summary>Guide for upgrading to version 4.x from 3.x</link-summary>\n    <card-summary>Guide for upgrading to version 4.x from 3.x</card-summary>\n    <web-summary>Guide for upgrading to version 4.x from 3.x</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <procedure title=\"High-Impact Changes\" id=\"high_impact_changes\">\n        <step><a href=\"#updating_dependencies\" /></step>\n        <step><a href=\"#rename_package_name\" /></step>\n        <step><a href=\"#changing_the_names_of_console_commands\" /></step>\n    </procedure>\n\n    <procedure title=\"Minor-Impact Changes\" id=\"minor_impact_changes\">\n        <step><a href=\"#names_migrate_constant_name_changed\" /></step>\n    </procedure>\n\n    <procedure title=\"Low-Impact Changes\" id=\"low_impact_changes\">\n        <step><a href=\"#changed_the_default_name_of_the_table_for_storing_actions\" /></step>\n    </procedure>\n\n    <chapter title=\"The easiest way to upgrade\" id=\"the_easiest_way_to_upgrade\">\n        <note>\n            If you used inheritance of actions from other actions, then you will need to process these files manually.\n        </note>\n\n        <p>\n            For your convenience, we have created an `upgrade` console command:\n        </p>\n\n        <code-block lang=\"bash\">\n            composer remove dragon-code/laravel-migration-actions\n            composer require dragon-code/laravel-actions:^4.0\n\n            %artisan% actions:upgrade\n            %artisan% migrate\n        </code-block>\n\n        <p>\n            It will do the following:\n        </p>\n\n        <list>\n            <li>Renaming manually invoked commands in a project to a new name</li>\n        </list>\n    </chapter>\n\n    <chapter title=\"Updating Dependencies\" id=\"updating_dependencies\">\n        <chapter title=\"Rename package name\" id=\"rename_package_name\">\n            <p>\n                You should update the following dependency in your application's <code>composer.json</code> file:\n            </p>\n\n            <p>\n                Replace:\n            </p>\n\n            <code-block lang=\"json\">\n                {\n                    \"require\": {\n                        \"dragon-code/laravel-migration-actions\": \"^3.0\"\n                    }\n                }\n            </code-block>\n\n            <p>\n                with:\n            </p>\n\n            <code-block lang=\"json\">\n                {\n                    \"require\": {\n                        \"dragon-code/laravel-actions\": \"^4.0\"\n                    }\n                }\n            </code-block>\n\n            <include from=\"snippets_composer.topic\" element-id=\"update\" />\n        </chapter>\n    </chapter>\n\n    <chapter title=\"Changing the names of console commands\" id=\"changing_the_names_of_console_commands\">\n        <table>\n            <tr>\n                <td>New Name</td>\n                <td>Old Name</td>\n            </tr>\n            <tr>\n                <td>%artisan% make:action</td>\n                <td>%artisan% make:migration:action</td>\n            </tr>\n            <tr>\n                <td>%artisan% actions</td>\n                <td>%artisan% migrate:actions</td>\n            </tr>\n            <tr>\n                <td>%artisan% actions:install</td>\n                <td>%artisan% migrate:actions:install</td>\n            </tr>\n            <tr>\n                <td>%artisan% actions:fresh</td>\n                <td>%artisan% migrate:actions:fresh</td>\n            </tr>\n            <tr>\n                <td>%artisan% actions:refresh</td>\n                <td>%artisan% migrate:actions:refresh</td>\n            </tr>\n            <tr>\n                <td>%artisan% actions:reset</td>\n                <td>%artisan% migrate:actions:reset</td>\n            </tr>\n            <tr>\n                <td>%artisan% actions:rollback</td>\n                <td>%artisan% migrate:actions:rollback</td>\n            </tr>\n            <tr>\n                <td>%artisan% actions:status</td>\n                <td>%artisan% migrate:actions:status</td>\n            </tr>\n            <tr>\n                <td>%artisan% actions:upgrade</td>\n                <td>%artisan% migrate:actions:upgrade</td>\n            </tr>\n        </table>\n    </chapter>\n\n    <chapter title=\"Names::MIGRATE constant name changed\" id=\"names_migrate_constant_name_changed\">\n        Replace <code>DragonCode\\LaravelActions\\Constants\\Names::MIGRATE</code>\n        with <code>DragonCode\\LaravelActions\\Constants\\Names::ACTIONS</code>\n    </chapter>\n\n    <chapter\n        title=\"Changed the default name of the table for storing actions\"\n        id=\"changed_the_default_name_of_the_table_for_storing_actions\">\n        <p>\n            The new table name is `actions`.\n        </p>\n\n        <p>\n            You can also specify any name in the application\n            <a href=\"https://github.com/TheDragonCode/laravel-deploy-operations/blob/4.x/config/actions.php\">settings</a> file.\n        </p>\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/upgrade-5.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Upgrading To 5.x from 4.x\" id=\"upgrade-5\">\n\n    <link-summary>Guide for upgrading to version 5.x from 4.x</link-summary>\n    <card-summary>Guide for upgrading to version 5.x from 4.x</card-summary>\n    <web-summary>Guide for upgrading to version 5.x from 4.x</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <procedure title=\"High-Impact Changes\" id=\"high_impact_changes\">\n        <step><a href=\"#updating_dependencies\" /></step>\n    </procedure>\n\n    <chapter title=\"Updating Dependencies\" id=\"updating_dependencies\">\n        <chapter title=\"PHP 8.2+ Required\" id=\"php_8_2_required\">\n            <format style=\"bold\">Deploy Actions</format>\n            now requires PHP 8.2.0 or greater.\n        </chapter>\n\n        <chapter title=\"Laravel 10+ Required\" id=\"laravel_10_required\">\n            <p>\n                <format style=\"bold\">Deploy Actions</format>\n                now requires Laravel 10.0 or greater.\n            </p>\n\n            <tip>\n                <p>\n                    If you are using Laravel 10, then you need to install the dependency:\n                </p>\n\n                <code-block lang=\"bash\">\n                    composer require doctrine/dbal\n                </code-block>\n            </tip>\n        </chapter>\n\n        <chapter title=\"Composer Dependencies\" id=\"composer_dependencies\">\n            <p>\n                You should update the following dependencies in your application's <code>composer.json</code> file:\n            </p>\n\n            <code-block lang=\"json\">\n                {\n                    \"require\": {\n                        \"dragon-code/laravel-actions\": \"^5.0\"\n                    }\n                }\n            </code-block>\n\n            <include from=\"snippets_composer.topic\" element-id=\"update\" />\n        </chapter>\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/upgrade-6.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Upgrading To 6.x from 5.x\" id=\"upgrade-6\">\n\n    <link-summary>Guide for upgrading to version 6.x from 5.x</link-summary>\n    <card-summary>Guide for upgrading to version 6.x from 5.x</card-summary>\n    <web-summary>Guide for upgrading to version 6.x from 5.x</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <procedure title=\"High-Impact Changes\" id=\"high_impact_changes\" type=\"choices\">\n        <step><a href=\"#updating_dependencies\" /></step>\n        <step><a href=\"#changed_the_namespace\" /></step>\n        <step><a href=\"#changed_the_name_of_the_main_class\" /></step>\n        <step><a href=\"#changed_names_of_console_commands\" /></step>\n        <step><a href=\"#changed_event_names\" /></step>\n        <step><a href=\"#configuration_file_name_changed\" /></step>\n    </procedure>\n\n    <procedure title=\"Minor-Impact Changes\" id=\"minor_impact_changes\">\n        <step><a href=\"#changed_directory_location\" /></step>\n        <step><a href=\"#database_transactions\" /></step>\n        <step><a href=\"#removed_async_property\" /></step>\n        <step><a href=\"#changed_property_typing_for_events\" /></step>\n        <step><a href=\"#removed_operations_stub_command\" /></step>\n    </procedure>\n\n    <procedure title=\"Low-Impact Changes\" id=\"low_impact_changes\">\n        <step><a href=\"#stub_name_changed\" /></step>\n    </procedure>\n\n    <chapter title=\"The Easiest way to upgrade\" id=\"the_easiest_way_to_upgrade\">\n        <note>\n            If you used inheritance of actions from other actions, then you will need to process these files manually.\n        </note>\n\n        <p>\n            For your convenience, we have created an <code>operations:upgrade</code> console command:\n        </p>\n\n        <code-block lang=\"bash\">\n            composer remove dragon-code/laravel-actions\n            composer require dragon-code/laravel-deploy-operations:^6.0\n            \n            %artisan% operations:upgrade\n            %artisan% migrate\n        </code-block>\n\n        <p>\n            It will do the following:\n        </p>\n\n        <list>\n            <li>Changing the old namespace of “actions” to a new one</li>\n            <li>Moves files to a new location</li>\n            <li>Updates the configuration file</li>\n            <li>Rename the stub file (if published)</li>\n        </list>\n\n        <p>\n            Please note that the script allows you to automate most of the actions, but may not complete them completely.\n            Therefore, you will need to manually check the result of the upgrade by checking this guide.\n        </p>\n    </chapter>\n\n    <chapter title=\"Updating Dependencies\" id=\"updating_dependencies\">\n        <p>\n            You should change the package name in the <code>composer.json</code> file from\n            <code>dragon-code/laravel-actions</code> to\n            <code>dragon-code/laravel-deploy-operations</code>, and also change its version to <code>^6.0</code>:\n        </p>\n\n        <code-block lang=\"json\">\n            {\n                \"require\": {\n                    \"dragon-code/laravel-deploy-operations\": \"^6.0\"\n                }\n            }\n        </code-block>\n\n        <include from=\"snippets_composer.topic\" element-id=\"update\" />\n    </chapter>\n\n    <chapter title=\"Changed the namespace\" id=\"changed_the_namespace\">\n        <p>\n            The namespace has been changed from <code>DragonCode\\LaravelActions</code> to\n            <code>DragonCode\\LaravelDeployOperations</code>.\n        </p>\n\n        You need to replace it in all actions of your application, as well as when using\n        <a href=\"events.topic\" />.\n    </chapter>\n\n    <chapter title=\"Changed the name of the main class\" id=\"changed_the_name_of_the_main_class\">\n        You should replace <code>DragonCode\\LaravelActions\\Action</code> namespace with\n        <code>DragonCode\\LaravelDeployOperations\\Operation</code>.\n    </chapter>\n\n    <chapter title=\"Changed names of console commands\" id=\"changed_names_of_console_commands\">\n        <table>\n            <tr>\n                <td>New Name</td>\n                <td>Old Name</td>\n            </tr>\n            <tr>\n                <td>make:operation</td>\n                <td>make:action</td>\n            </tr>\n            <tr>\n                <td>operations</td>\n                <td>actions</td>\n            </tr>\n            <tr>\n                <td>operations:fresh</td>\n                <td>actions:fresh</td>\n            </tr>\n            <tr>\n                <td>operations:install</td>\n                <td>actions:install</td>\n            </tr>\n            <tr>\n                <td>operations:refresh</td>\n                <td>actions:refresh</td>\n            </tr>\n            <tr>\n                <td>operations:reset</td>\n                <td>actions:reset</td>\n            </tr>\n            <tr>\n                <td>operations:rollback</td>\n                <td>actions:rollback</td>\n            </tr>\n            <tr>\n                <td>operations:status</td>\n                <td>actions:status</td>\n            </tr>\n            <tr>\n                <td>operations:stub</td>\n                <td>actions:stub</td>\n            </tr>\n            <tr>\n                <td>operations:upgrade</td>\n                <td>actions:upgrade</td>\n            </tr>\n        </table>\n    </chapter>\n\n    <chapter title=\"Changed event names\" id=\"changed_event_names\">\n        <table>\n            <tr>\n                <td>New Name</td>\n                <td>Old Name</td>\n            </tr>\n\n            <tr>\n                <td>DeployOperationStarted</td>\n                <td>ActionStarted</td>\n            </tr>\n            <tr>\n                <td>DeployOperationEnded</td>\n                <td>ActionEnded</td>\n            </tr>\n            <tr>\n                <td>DeployOperationFailed</td>\n                <td>ActionFailed</td>\n            </tr>\n            <tr>\n                <td>NoPendingDeployOperations</td>\n                <td>NoPendingActions</td>\n            </tr>\n        </table>\n\n        <p>\n            Don't forget to also change the namespace from <code>DragonCode\\LaravelActions\\Events</code> to\n            <code>DragonCode\\LaravelDeployOperations\\Events</code>.\n        </p>\n    </chapter>\n\n    <chapter title=\"Changed property typing for events\" id=\"changed_property_typing_for_events\">\n        <p>\n            The type of the <code>method</code> property for events has been changed.\n        </p>\n\n        <chapter title=\"Before\" id=\"before\">\n            <code-block lang=\"php\">\n                use DragonCode\\LaravelActions\\Events\\ActionEnded;\n                use DragonCode\\LaravelDeployOperations\\Enums\\MethodEnum;\n\n                /** @var ActionEnded */\n                $event->method; // is string\n            </code-block>\n        </chapter>\n\n        <chapter title=\"After\" id=\"after\">\n            <code-block lang=\"php\">\n                use DragonCode\\LaravelDeployOperations\\Enums\\MethodEnum;\n                use DragonCode\\LaravelDeployOperations\\Events\\DeployOperationEnded;\n\n                /** @var DeployOperationEnded */\n                $event->method; // is MethodEnum\n            </code-block>\n        </chapter>\n    </chapter>\n\n    <chapter title=\"Configuration file name changed\" id=\"configuration_file_name_changed\">\n        <p>\n            We recommend that you delete the old configuration file\n            <code>config/actions.php</code> and publish a new one.\n            This way you will see the changes made to it.\n        </p>\n\n        <code-block lang=\"bash\">\n            %artisan% vendor:publish --provider=\"DragonCode\\LaravelDeployOperations\\ServiceProvider\"\n        </code-block>\n    </chapter>\n\n    <chapter title=\"Changed names of constants\" id=\"changed_names_of_constants\">\n        <p>\n            If you use package constant references, you must also rename them.\n        </p>\n\n        <p>\n            The old name was in <code>UPPER_CASE</code>, the new one was in <code>PascalCase</code>.\n        </p>\n\n        <p>\n            For example:\n        </p>\n\n        <code-block lang=\"php\">\n            // Old\n            class Names\n            {\n                public const ACTIONS = 'actions';\n                public const FRESH   = 'actions:fresh';\n                // ...\n            }\n        </code-block>\n        <code-block lang=\"php\">\n            // New\n            class Names\n            {\n                public const Fresh      = 'operations:fresh';\n                public const Operations = 'operations';\n                // ...\n            }\n        </code-block>\n    </chapter>\n\n    <chapter title=\"Changed directory location\" id=\"changed_directory_location\">\n        File storage directory changed to <code>/operations</code> from <code>/actions</code>.\n    </chapter>\n\n    <chapter title=\"Database transactions\" id=\"database_transactions\">\n        <p>\n            The following properties have been removed:\n        </p>\n\n        <list>\n            <li><code>$transactions</code></li>\n            <li><code>$transactionAttempts</code></li>\n        </list>\n\n        <p>\n            Instead, you can use the <code>hasTransactions</code> and <code>transactionAttempts</code> methods.\n        </p>\n\n        <p>\n            The <code>enabledTransactions</code> method has been renamed to <code>hasTransactions</code>.\n        </p>\n    </chapter>\n\n    <chapter title=\"Removed $async property\" id=\"removed_async_property\">\n        The <code>$async</code> property has been removed from the base class.\n        You can use the previously available <code>isAsync</code> method instead.\n    </chapter>\n\n    <chapter title=\"Stub name changed\" id=\"stub_name_changed\">\n        If you published a stub file, then you also need to rename it from <code>stubs/action.stub</code> to\n        <code>stubs/deploy-operation.stub</code> and make changes to its structure.\n    </chapter>\n\n    <chapter title=\"Removed operations:stub command\" id=\"removed_operations_stub_command\">\n        <p>\n            The <code>%artisan% operations:stub</code> console command has been removed. Use another command instead:\n        </p>\n\n        <code-block lang=\"bash\">\n            %artisan% vendor:publish --tag=stubs --provider=\"DragonCode\\LaravelDeployOperations\\ServiceProvider\"\n        </code-block>\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/upgrade-7.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Upgrading To 7.x from 6.x\" id=\"upgrade-7\">\n\n    <link-summary>Guide for upgrading to version 7.x from 6.x</link-summary>\n    <card-summary>Guide for upgrading to version 7.x from 6.x</card-summary>\n    <web-summary>Guide for upgrading to version 7.x from 6.x</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <procedure title=\"High-Impact Changes\" id=\"high_impact_changes\" type=\"choices\">\n        <step><a href=\"#updating_dependencies\" /></step>\n        <step><a href=\"#strict_typification\" /></step>\n        <step><a href=\"#removed_deprecated_methods_and_properties\" /></step>\n    </procedure>\n\n    <procedure title=\"Minor-Impact Changes\" id=\"minor_impact_changes\">\n        <step><a href=\"#laravel_10_is_now_unsupported\" /></step>\n        <step><a href=\"#removed_operations_upgrade_console_command\" /></step>\n        <step><a href=\"#removed_operations_refresh_console_command\" /></step>\n        <step><a href=\"#removed_operations_reset_console_command\" /></step>\n    </procedure>\n\n    <procedure title=\"Low-Impact Changes\" id=\"low_impact_changes\">\n        <step><a href=\"#added_suffixes_for_classes\" /></step>\n        <step><a href=\"#renamed_traits\" /></step>\n        <step><a href=\"#replaced_config_helper_with_config_data\" /></step>\n        <step><a href=\"#replaced_dragon_code_simple_dto_with_spatie_laravel_data\" /></step>\n    </procedure>\n\n    <chapter title=\"Updating Dependencies\" id=\"updating_dependencies\">\n        <p>\n            You should update the following dependencies in your application's <code>composer.json</code> file:\n        </p>\n\n        <code-block lang=\"json\">\n            {\n                \"require\": {\n                    \"dragon-code/laravel-deploy-operations\": \"^7.0\"\n                }\n            }\n        </code-block>\n\n        <include from=\"snippets_composer.topic\" element-id=\"update\" />\n    </chapter>\n\n    <chapter title=\"Laravel 10 is now unsupported\" id=\"laravel_10_is_now_unsupported\">\n        Laravel 10 version is no longer supported due to the lack of event classes required for\n        <format style=\"bold\">%product_short%</format>\n        .\n    </chapter>\n\n    <chapter title=\"Removed `operations:upgrade` console command\" id=\"removed_operations_upgrade_console_command\">\n        We decided to drop support for the <code>php artisan operations:upgrade</code> console command.\n        It does not exist now.\n    </chapter>\n\n    <chapter title=\"Removed `operations:refresh` console command\" id=\"removed_operations_refresh_console_command\">\n        We decided to drop support for the <code>php artisan operations:refresh</code> console command.\n        It does not exist now.\n    </chapter>\n\n    <chapter title=\"Removed `operations:reset` console command\" id=\"removed_operations_reset_console_command\">\n        We decided to drop support for the <code>php artisan operations:reset</code> console command.\n        It does not exist now.\n    </chapter>\n\n    <chapter title=\"Strict typification\" id=\"strict_typification\">\n        <p>\n            A strict typification has been added to all the project files.\n        </p>\n\n        <code-block lang=\"php\">\n            declare(strict_types=1);\n        </code-block>\n    </chapter>\n\n    <chapter title=\"Replaced `ConfigHelper` with `ConfigData`\" id=\"replaced_config_helper_with_config_data\">\n        <p>\n            The <code>DragonCode\\LaravelDeployOperations\\Helpers\\ConfigHelper</code> class has been removed and\n            <code>DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData</code>, which is a Data object, is now used instead.\n        </p>\n\n        <p>\n            For example,\n        </p>\n\n        <code-block lang=\"diff\">\n            - $this->config->path('some'); // /operations/some\n            - config('deploy-operations.transactions.enabled'); // false\n            - config('deploy-operations.async'); // false\n            \n            + $this->config->path . 'some'; // /operations/some\n            + $this->config->transactions->enabled; // false\n            + $this->config->async; // false\n        </code-block>\n    </chapter>\n\n    <chapter\n        title=\"Replaced `dragon-code/simple-dto` with `spatie/laravel-data\n    `\" id=\"replaced_dragon_code_simple_dto_with_spatie_laravel_data\">\n        <p>\n            This tidied up the handling of settings and options.\n        </p>\n        <p>\n            If you used a direct reference to the <code>Helpers/Config</code> and\n            <code>Values/Options</code> classes, update your code.\n        </p>\n    </chapter>\n\n    <chapter title=\"Added suffixes for classes\" id=\"added_suffixes_for_classes\">\n        <compare>\n            <code-block lang=\"php\">\n                Console\\Install\n                Console\\Make\n                Console\\Operations\n                Console\\Fresh\n                Console\\Rollback\n                Console\\Status\n                Processors\\Fresh\n                Processors\\Install\n                Processors\\Make\n                Processors\\Operations\n                Processors\\Rollback\n                Processors\\Status\n                Helpers\\Config\n                Helpers\\Git\n                Helpers\\Sorter\n                Services\\Migrator\n                Services\\Mutex\n                Values\\Options\n            </code-block>\n            <code-block lang=\"php\">\n                Console\\InstallCommand\n                Console\\MakeCommand\n                Console\\OperationsCommand\n                Console\\FreshCommand\n                Console\\RollbackCommand\n                Console\\StatusCommand\n                Processors\\FreshProcessor\n                Processors\\InstallProcessor\n                Processors\\MakeProcessor\n                Processors\\OperationsProcessor\n                Processors\\RollbackProcessor\n                Processors\\StatusProcessor\n                Data\\Config\\ConfigData\n                Helpers\\GitHelper\n                Helpers\\SorterHelper\n                Services\\MigratorService\n                Services\\MutexService\n                Data\\OptionsData\n            </code-block>\n        </compare>\n    </chapter>\n\n    <chapter title=\"Renamed traits\" id=\"renamed_traits\">\n        <compare>\n            <code-block lang=\"php\">\n                Concerns\\About\n                Concerns\\Artisan\n                Concerns\\Isolatable\n                Concerns\\Optionable\n            </code-block>\n            <code-block lang=\"php\">\n                Concerns\\HasAbout\n                Concerns\\HasArtisan\n                Concerns\\HasIsolatable\n                Concerns\\HasOptionable\n            </code-block>\n        </compare>\n    </chapter>\n\n    <chapter title=\"Removed deprecated methods and properties\" id=\"removed_deprecated_methods_and_properties\">\n        <p>\n            The following properties and methods have been removed from the\n            <code>DragonCode\\LaravelDeployOperations\\Operation</code>\n            class:\n        </p>\n\n        <compare>\n            <code-block lang=\"php\">\n                protected bool $once\n                protected array|string | null $environment\n                protected array|string | null $exceptEnvironment\n                protected bool $before\n                public function getConnection(): ?string\n                public function isOnce(): bool\n                public function enabledTransactions(): bool\n                public function transactionAttempts(): int\n                public function onEnvironment(): array\n                public function exceptEnvironment(): array\n                public function allow(): bool\n                public function hasBefore(): bool\n                public function isAsync(): bool\n            </code-block>\n            <code-block lang=\"php\">\n                public function shouldOnce(): bool\n                public function shouldRun(): bool\n                public function shouldRun(): bool\n                public function needBefore(): bool\n                Not used\n                public bool shouldOnce(): bool\n                public function withinTransactions(): bool\n                It is indicated in the settings\n                public function shouldRun(): bool\n                public function shouldRun(): bool\n                public function shouldRun(): bool\n                public function needBefore(): bool\n                public function needAsync(): bool\n            </code-block>\n        </compare>\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/topics/usage.topic",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE topic\n    SYSTEM \"https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd\">\n<topic\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd\"\n    title=\"Usage\" id=\"usage\">\n\n    <link-summary>Information on how to use %product_short%</link-summary>\n    <card-summary>Information on how to use %product_short%</card-summary>\n    <web-summary>Information on how to use %product_short%</web-summary>\n\n    <show-structure depth=\"2\" />\n\n    <chapter title=\"Creating Operation\" id=\"creating_operation\">\n        <include from=\"creating-operations.topic\" element-id=\"creating\" />\n    </chapter>\n\n    <chapter title=\"Running Operation\" id=\"running_operation\">\n        <include from=\"running-operations.topic\" element-id=\"run_all\" />\n    </chapter>\n</topic>\n"
  },
  {
    "path": "docs/v.list",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE vars SYSTEM \"https://resources.jetbrains.com/writerside/1.0/vars.dtd\">\n<vars>\n    <var name=\"product\" value=\"🚀 Laravel Deploy Operations\" />\n    <var name=\"product_short\" value=\"Deploy Operations\" />\n\n    <var name=\"package_name\" value=\"dragon-code/laravel-deploy-operations\" />\n\n    <var name=\"command_make\" value=\"make:operation\" />\n    <var name=\"command_run\" value=\"operations\" />\n    <var name=\"command_fresh\" value=\"operations:fresh\" />\n    <var name=\"command_rollback\" value=\"operations:rollback\" />\n    <var name=\"command_status\" value=\"operations:status\" />\n    <var name=\"command_install\" value=\"operations:install\" />\n\n    <var name=\"artisan\" value=\"php artisan\" />\n\n    <var name=\"vendor_publish\" value=\"%artisan% vendor:publish --tag deploy-operations\" />\n\n    <var name=\"config\" value=\"config/localization.php\" />\n    <var name=\"directory\" value=\"/operations\" />\n    <var name=\"table\" value=\"operations\" />\n    <var name=\"transactions_attempts\" value=\"1\" />\n\n    <var name=\"badge_not_supported\" value=\"badge-not-supported.svg\" />\n    <var name=\"badge_supported\" value=\"badge-supported.svg\" />\n\n    <var\n            name=\"config_url\"\n            value=\"https://github.com/TheDragonCode/laravel-deploy-operations/blob/main/config/deploy-operations.php\"\n    />\n\n    <var name=\"year\" value=\"2025\" />\n</vars>\n"
  },
  {
    "path": "docs/versions.json",
    "content": "[\n    {\n        \"version\": \"7.x\",\n        \"url\": \"https://deploy-operations.dragon-code.pro\",\n        \"isCurrent\": true\n    },\n    {\n        \"version\": \"6.x\",\n        \"url\": \"https://github.com/TheDragonCode/laravel-deploy-operations/tree/6.x/docs\",\n        \"isCurrent\": false\n    },\n    {\n        \"version\": \"5.x\",\n        \"url\": \"https://github.com/TheDragonCode/laravel-deploy-operations/tree/5.x/docs\",\n        \"isCurrent\": false\n    },\n    {\n        \"version\": \"4.x\",\n        \"url\": \"https://github.com/TheDragonCode/laravel-deploy-operations/tree/4.x/docs\",\n        \"isCurrent\": false\n    },\n    {\n        \"version\": \"3.x\",\n        \"url\": \"https://github.com/TheDragonCode/laravel-deploy-operations/tree/3.x/docs\",\n        \"isCurrent\": false\n    }\n]\n"
  },
  {
    "path": "docs/writerside.cfg",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE ihp SYSTEM \"https://resources.jetbrains.com/writerside/1.0/ihp.dtd\">\n\n<ihp version=\"2.0\">\n    <topics dir=\"topics\" />\n    <images dir=\"images\" />\n    <snippets src=\"snippets\" />\n\n    <instance src=\"do.tree\" version=\"7.x\" />\n    <instance src=\"docs_libraries.tree\" />\n</ihp>\n"
  },
  {
    "path": "ide.json",
    "content": "{\n    \"$schema\": \"https://laravel-ide.com/schema/laravel-ide-v2.json\",\n    \"codeGenerations\": [\n        {\n            \"id\": \"dragon-code.create-deploy-operation\",\n            \"name\": \"Create Deploy Operation\",\n            \"inputFilter\": \"deploy-operations\",\n            \"regex\": \".+\",\n            \"files\": [\n                {\n                    \"directory\": \"/operations\",\n                    \"name\": \"${CURRENT_TIME|format:yyyy_MM_dd_HHmmss}_${INPUT_CLASS|className|replace: ,_|upperCamelCase|snakeCase}.php\",\n                    \"template\": {\n                        \"type\": \"stub\",\n                        \"path\": \"/stubs/deploy-operation.stub\",\n                        \"fallbackPath\": \"resources/stubs/deploy-operation.stub\"\n                    }\n                }\n            ]\n        }\n    ],\n    \"completions\": [\n        {\n            \"complete\": \"directoryFiles\",\n            \"condition\": [\n                {\n                    \"classFqn\": [\n                        \"DragonCode\\\\LaravelDeployOperations\\\\Helpers\\\\OperationHelper\"\n                    ],\n                    \"methodNames\": [\n                        \"run\"\n                    ],\n                    \"functionFqn\": [\n                        \"DragonCode\\\\LaravelDeployOperations\\\\operation\"\n                    ],\n                    \"place\": \"parameter\",\n                    \"parameters\": [\n                        1\n                    ]\n                }\n            ],\n            \"options\": {\n                \"directory\": \"/operations\",\n                \"suffixToClear\": \".php\",\n                \"recursive\": true\n            }\n        }\n    ]\n}\n"
  },
  {
    "path": "phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit\n        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xsi:noNamespaceSchemaLocation=\"vendor/phpunit/phpunit/phpunit.xsd\"\n        bootstrap=\"vendor/autoload.php\"\n        cacheResult=\"false\"\n        colors=\"true\"\n>\n    <php>\n        <env name=\"APP_KEY\" value=\"AckfSECXIvnK5r28GVIWUAxmbBSjTsmF\"/>\n        <env name=\"APP_ENV\" value=\"testing\"/>\n    </php>\n    <testsuites>\n        <testsuite name=\"Test Suite\">\n            <directory>./tests</directory>\n        </testsuite>\n    </testsuites>\n    <source>\n        <include>\n            <directory>./src</directory>\n        </include>\n    </source>\n</phpunit>\n"
  },
  {
    "path": "pint.json",
    "content": "{\n    \"preset\": \"laravel\",\n    \"exclude\": [\n        \"tests/Fixtures\"\n    ],\n    \"rules\": {\n        \"@PHP7x1Migration\": true,\n        \"@PHP7x3Migration\": true,\n        \"@PHP7x4Migration\": true,\n        \"@PHP8x0Migration\": true,\n        \"@PHP8x1Migration\": true,\n        \"@PHP8x2Migration\": true,\n        \"concat_space\": {\n            \"spacing\": \"one\"\n        },\n        \"blank_line_before_statement\": {\n            \"statements\": [\n                \"declare\",\n                \"phpdoc\",\n                \"continue\",\n                \"return\"\n            ]\n        },\n        \"class_attributes_separation\": {\n            \"elements\": {\n                \"case\": \"none\",\n                \"const\": \"none\",\n                \"method\": \"one\",\n                \"property\": \"one\",\n                \"trait_import\": \"none\"\n            }\n        },\n        \"class_definition\": {\n            \"multi_line_extends_each_single_line\": true,\n            \"single_item_single_line\": true,\n            \"single_line\": true,\n            \"space_before_parenthesis\": true\n        },\n        \"combine_consecutive_issets\": true,\n        \"combine_consecutive_unsets\": true,\n        \"braces_position\": {\n            \"allow_single_line_anonymous_functions\": true,\n            \"allow_single_line_empty_anonymous_classes\": true,\n            \"anonymous_classes_opening_brace\": \"same_line\"\n        },\n        \"escape_implicit_backslashes\": {\n            \"double_quoted\": true,\n            \"heredoc_syntax\": true,\n            \"single_quoted\": false\n        },\n        \"global_namespace_import\": {\n            \"import_classes\": true,\n            \"import_constants\": true,\n            \"import_functions\": true\n        },\n        \"multiline_comment_opening_closing\": true,\n        \"no_superfluous_elseif\": true,\n        \"no_useless_else\": true,\n        \"operator_linebreak\": {\n            \"only_booleans\": false\n        },\n        \"ordered_types\": {\n            \"null_adjustment\": \"always_last\",\n            \"sort_algorithm\": \"alpha\"\n        },\n        \"phpdoc_line_span\": {\n            \"case\": \"single\",\n            \"class\": \"single\",\n            \"const\": \"single\",\n            \"method\": \"single\",\n            \"property\": \"single\",\n            \"other\": \"single\"\n        },\n        \"return_assignment\": true,\n        \"simplified_if_return\": true,\n        \"phpdoc_param_order\": true,\n        \"fully_qualified_strict_types\": true,\n        \"declare_strict_types\": true,\n        \"types_spaces\": {\n            \"space_multiple_catch\": \"none\"\n        },\n        \"binary_operator_spaces\": {\n            \"default\": \"align_single_space_minimal\"\n        },\n        \"php_unit_method_casing\": {\n            \"case\": \"camel_case\"\n        }\n    }\n}\n"
  },
  {
    "path": "resources/stubs/deploy-operation.stub",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke(): void\n    {\n        //\n    }\n};\n"
  },
  {
    "path": "src/Concerns/ConfirmableTrait.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Concerns;\n\nuse Illuminate\\Console\\ConfirmableTrait as BaseConfirmableTrait;\n\ntrait ConfirmableTrait\n{\n    use BaseConfirmableTrait;\n\n    protected bool $secure = true;\n\n    protected function allowToProceed(): bool\n    {\n        return ! $this->secure || $this->confirmToProceed();\n    }\n}\n"
  },
  {
    "path": "src/Concerns/HasAbout.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Concerns;\n\nuse Composer\\InstalledVersions;\nuse DragonCode\\Support\\Facades\\Helpers\\Str;\nuse Illuminate\\Foundation\\Console\\AboutCommand;\n\ntrait HasAbout\n{\n    protected string $packageName = 'dragon-code/laravel-deploy-operations';\n\n    protected function registerAbout(): void\n    {\n        AboutCommand::add($this->getPackageName(), fn () => [\n            'Version' => $this->getPackageVersion(),\n        ]);\n    }\n\n    protected function getPackageName(): string\n    {\n        return Str::of($this->packageName)\n            ->after('/')\n            ->snake()\n            ->replace('_', ' ')\n            ->title()\n            ->toString();\n    }\n\n    protected function getPackageVersion(): string\n    {\n        return InstalledVersions::getPrettyVersion($this->packageName);\n    }\n}\n"
  },
  {
    "path": "src/Concerns/HasArtisan.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Concerns;\n\nuse Illuminate\\Console\\OutputStyle;\nuse Illuminate\\Support\\Facades\\Artisan;\n\ntrait HasArtisan\n{\n    protected function artisan(string $command, array $parameters = [], ?OutputStyle $outputBuffer = null): void\n    {\n        Artisan::call($command, $parameters, $outputBuffer);\n    }\n}\n"
  },
  {
    "path": "src/Concerns/HasIsolatable.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Concerns;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\LaravelDeployOperations\\Services\\MutexService;\n\nuse function app;\nuse function is_numeric;\n\ntrait HasIsolatable\n{\n    protected function isolationMutex(): MutexService\n    {\n        return app(MutexService::class);\n    }\n\n    protected function isolatedStatusCode(): int\n    {\n        if ($isolate = $this->getIsolateOption()) {\n            return is_numeric($isolate) ? $isolate : self::SUCCESS;\n        }\n\n        return self::SUCCESS;\n    }\n\n    protected function getIsolateOption(): bool|int\n    {\n        return $this->hasIsolateOption() ? (int) $this->option(Options::Isolated) : false;\n    }\n\n    protected function hasIsolateOption(): bool\n    {\n        return $this->hasOption(Options::Isolated) && $this->option(Options::Isolated);\n    }\n}\n"
  },
  {
    "path": "src/Concerns/HasOptionable.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Concerns;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\Support\\Facades\\Helpers\\Arr;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nuse function in_array;\n\n/** @mixin \\DragonCode\\LaravelDeployOperations\\Console\\Command */\ntrait HasOptionable\n{\n    protected array $arguments = [];\n\n    protected array $options = [\n        Options::Connection,\n        Options::Force,\n        Options::Mute,\n        Options::Isolated,\n    ];\n\n    protected function configure(): void\n    {\n        $this->specifyParameters();\n    }\n\n    protected function getOptions(): array\n    {\n        return Arr::of($this->availableOptions())\n            ->filter(fn (array $option) => in_array($option[0], $this->options, true))\n            ->toArray();\n    }\n\n    protected function getArguments(): array\n    {\n        return Arr::of($this->availableArguments())\n            ->filter(fn (array $argument) => in_array($argument[0], $this->arguments, true))\n            ->toArray();\n    }\n\n    protected function availableArguments(): array\n    {\n        return [\n            [\n                Options::Name,\n                InputArgument::OPTIONAL,\n                'The name of the operation',\n            ],\n        ];\n    }\n\n    protected function availableOptions(): array\n    {\n        return [\n            [\n                Options::Before,\n                null,\n                InputOption::VALUE_NONE,\n                'Run operations marked as before',\n            ],\n            [\n                Options::Connection,\n                null,\n                InputOption::VALUE_OPTIONAL,\n                'The database connection to use',\n            ],\n            [\n                Options::Force,\n                null,\n                InputOption::VALUE_NONE,\n                'Force the operation to run when in production',\n            ],\n            [\n                Options::Path,\n                null,\n                InputOption::VALUE_OPTIONAL,\n                'The path to the operations files to be executed',\n            ],\n            [\n                Options::Realpath,\n                null,\n                InputOption::VALUE_NONE,\n                'Indicate any provided operation file paths are pre-resolved absolute path',\n            ],\n            [\n                Options::Step,\n                null,\n                InputOption::VALUE_OPTIONAL,\n                'Force the operations to be run so they can be rolled back individually',\n            ],\n            [\n                Options::Mute,\n                null,\n                InputOption::VALUE_NONE,\n                'Turns off the output of informational messages',\n            ],\n            [\n                Options::Isolated,\n                null,\n                InputOption::VALUE_OPTIONAL,\n                'Do not run the operations command if another instance of the operations command is already running',\n                false,\n            ],\n            [\n                Options::Sync,\n                null,\n                InputOption::VALUE_OPTIONAL,\n                'Makes all operations run synchronously',\n                false,\n            ],\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Console/Command.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Console;\n\nuse DragonCode\\LaravelDeployOperations\\Concerns\\ConfirmableTrait;\nuse DragonCode\\LaravelDeployOperations\\Concerns\\HasIsolatable;\nuse DragonCode\\LaravelDeployOperations\\Concerns\\HasOptionable;\nuse DragonCode\\LaravelDeployOperations\\Data\\OptionsData;\nuse DragonCode\\LaravelDeployOperations\\Processors\\Processor;\nuse Illuminate\\Console\\Command as BaseCommand;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\nuse function app;\nuse function array_merge;\nuse function sprintf;\n\nabstract class Command extends BaseCommand\n{\n    use ConfirmableTrait;\n    use HasIsolatable;\n    use HasOptionable;\n\n    protected Processor|string $processor;\n\n    public function handle(): int\n    {\n        if ($this->allowToProceed()) {\n            $this->resolveProcessor()->handle();\n\n            return self::SUCCESS;\n        }\n\n        return self::FAILURE;\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        if ($this->getIsolateOption() !== false && ! $this->isolationMutex()->create($this)) {\n            $this->comment(sprintf('The [%s] command is already running.', $this->getName()));\n\n            return $this->isolatedStatusCode();\n        }\n\n        try {\n            return parent::execute($input, $output);\n        } finally {\n            if ($this->getIsolateOption() !== false) {\n                $this->isolationMutex()->forget($this);\n            }\n        }\n    }\n\n    protected function resolveProcessor(): Processor\n    {\n        return app($this->processor, [\n            'options' => $this->getOptionsData(),\n            'input'   => $this->input,\n            'output'  => $this->output,\n        ]);\n    }\n\n    protected function getOptionsData(): OptionsData\n    {\n        return OptionsData::from(array_merge($this->options(), $this->arguments()));\n    }\n}\n"
  },
  {
    "path": "src/Console/FreshCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Console;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\LaravelDeployOperations\\Processors\\FreshProcessor;\nuse DragonCode\\LaravelDeployOperations\\Processors\\Processor;\n\nclass FreshCommand extends Command\n{\n    protected $name = Names::Fresh;\n\n    protected $description = 'Drop and re-run all deploy operations';\n\n    protected Processor|string $processor = FreshProcessor::class;\n\n    protected array $options = [\n        Options::Connection,\n        Options::Force,\n        Options::Path,\n        Options::Realpath,\n        Options::Mute,\n        Options::Isolated,\n    ];\n}\n"
  },
  {
    "path": "src/Console/InstallCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Console;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Processors\\InstallProcessor;\nuse DragonCode\\LaravelDeployOperations\\Processors\\Processor;\n\nclass InstallCommand extends Command\n{\n    protected $name = Names::Install;\n\n    protected $description = 'Create the deploy operations repository';\n\n    protected Processor|string $processor = InstallProcessor::class;\n}\n"
  },
  {
    "path": "src/Console/MakeCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Console;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\LaravelDeployOperations\\Processors\\MakeProcessor;\nuse DragonCode\\LaravelDeployOperations\\Processors\\Processor;\n\nclass MakeCommand extends Command\n{\n    protected $signature = Names::Make;\n\n    protected $description = 'Create a new deploy operation file';\n\n    protected Processor|string $processor = MakeProcessor::class;\n\n    protected array $arguments = [\n        Options::Name,\n    ];\n\n    protected array $options = [\n        Options::Connection,\n        Options::Force,\n        Options::Path,\n        Options::Realpath,\n        Options::Mute,\n    ];\n}\n"
  },
  {
    "path": "src/Console/OperationsCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Console;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\LaravelDeployOperations\\Processors\\OperationsProcessor;\nuse DragonCode\\LaravelDeployOperations\\Processors\\Processor;\n\nclass OperationsCommand extends Command\n{\n    protected $signature = Names::Operations;\n\n    protected $description = 'Run the deploy operations';\n\n    protected Processor|string $processor = OperationsProcessor::class;\n\n    protected bool $secure = false;\n\n    protected array $options = [\n        Options::Before,\n        Options::Connection,\n        Options::Path,\n        Options::Realpath,\n        Options::Mute,\n        Options::Isolated,\n        Options::Sync,\n    ];\n}\n"
  },
  {
    "path": "src/Console/RollbackCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Console;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\LaravelDeployOperations\\Processors\\Processor;\nuse DragonCode\\LaravelDeployOperations\\Processors\\RollbackProcessor;\n\nclass RollbackCommand extends Command\n{\n    protected $name = Names::Rollback;\n\n    protected $description = 'Rollback the last deploy operation';\n\n    protected Processor|string $processor = RollbackProcessor::class;\n\n    protected array $options = [\n        Options::Connection,\n        Options::Force,\n        Options::Path,\n        Options::Realpath,\n        Options::Step,\n        Options::Mute,\n        Options::Isolated,\n    ];\n}\n"
  },
  {
    "path": "src/Console/StatusCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Console;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\LaravelDeployOperations\\Processors\\Processor;\nuse DragonCode\\LaravelDeployOperations\\Processors\\StatusProcessor;\n\nclass StatusCommand extends Command\n{\n    protected $name = Names::Status;\n\n    protected $description = 'Show the status of each deploy operation';\n\n    protected Processor|string $processor = StatusProcessor::class;\n\n    protected bool $secure = false;\n\n    protected array $options = [\n        Options::Connection,\n        Options::Path,\n        Options::Realpath,\n        Options::Mute,\n    ];\n}\n"
  },
  {
    "path": "src/Constants/Names.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Constants;\n\nclass Names\n{\n    public const Operations = 'operations';\n    public const Fresh      = 'operations:fresh';\n    public const Install    = 'operations:install';\n    public const Make       = 'make:operation';\n    public const Rollback   = 'operations:rollback';\n    public const Status     = 'operations:status';\n}\n"
  },
  {
    "path": "src/Constants/Options.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Constants;\n\nclass Options\n{\n    public const Before     = 'before';\n    public const Connection = 'connection';\n    public const Force      = 'force';\n    public const Isolated   = 'isolated';\n    public const Mute       = 'mute';\n    public const Name       = 'name';\n    public const Path       = 'path';\n    public const Realpath   = 'realpath';\n    public const Step       = 'step';\n    public const Sync       = 'sync';\n}\n"
  },
  {
    "path": "src/Constants/Order.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Constants;\n\nclass Order\n{\n    public const Asc  = 'asc';\n    public const Desc = 'desc';\n}\n"
  },
  {
    "path": "src/Data/Casts/BoolCast.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data\\Casts;\n\nuse DragonCode\\Support\\Facades\\Helpers\\Boolean;\nuse Spatie\\LaravelData\\Casts\\Cast;\nuse Spatie\\LaravelData\\Support\\Creation\\CreationContext;\nuse Spatie\\LaravelData\\Support\\DataProperty;\n\nclass BoolCast implements Cast\n{\n    public function cast(DataProperty $property, mixed $value, array $properties, CreationContext $context): bool\n    {\n        return Boolean::parse($value);\n    }\n}\n"
  },
  {
    "path": "src/Data/Casts/Config/ExcludeCast.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data\\Casts\\Config;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Str;\nuse Spatie\\LaravelData\\Casts\\Cast;\nuse Spatie\\LaravelData\\Support\\Creation\\CreationContext;\nuse Spatie\\LaravelData\\Support\\DataProperty;\n\nclass ExcludeCast implements Cast\n{\n    public function cast(DataProperty $property, mixed $value, array $properties, CreationContext $context): array\n    {\n        return (new Collection($value))\n            ->map(static fn (string $path) => Str::replace(['\\\\', '/'], DIRECTORY_SEPARATOR, $path))\n            ->filter()\n            ->all();\n    }\n}\n"
  },
  {
    "path": "src/Data/Casts/Config/PathCast.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data\\Casts\\Config;\n\nuse Spatie\\LaravelData\\Casts\\Cast;\nuse Spatie\\LaravelData\\Support\\Creation\\CreationContext;\nuse Spatie\\LaravelData\\Support\\DataProperty;\n\nuse function rtrim;\n\nclass PathCast implements Cast\n{\n    public function cast(DataProperty $property, mixed $value, array $properties, CreationContext $context): string\n    {\n        return rtrim($value, '\\\\/') . DIRECTORY_SEPARATOR;\n    }\n}\n"
  },
  {
    "path": "src/Data/Casts/OperationNameCast.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data\\Casts;\n\nuse DragonCode\\Support\\Facades\\Helpers\\Str;\nuse Spatie\\LaravelData\\Casts\\Cast;\nuse Spatie\\LaravelData\\Support\\Creation\\CreationContext;\nuse Spatie\\LaravelData\\Support\\DataProperty;\n\nclass OperationNameCast implements Cast\n{\n    public function cast(DataProperty $property, mixed $value, array $properties, CreationContext $context): ?string\n    {\n        if (empty($value)) {\n            return null;\n        }\n\n        return Str::of($value)\n            ->replace('\\\\', '/')\n            ->replace('.php', '')\n            ->explode('/')\n            ->map(fn (string $path) => Str::snake($path))\n            ->implode(DIRECTORY_SEPARATOR)\n            ->toString();\n    }\n}\n"
  },
  {
    "path": "src/Data/Casts/PathCast.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data\\Casts;\n\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse Illuminate\\Support\\Str;\nuse Spatie\\LaravelData\\Casts\\Cast;\nuse Spatie\\LaravelData\\Support\\Creation\\CreationContext;\nuse Spatie\\LaravelData\\Support\\DataProperty;\n\nuse function app;\nuse function realpath;\n\nclass PathCast implements Cast\n{\n    public function cast(DataProperty $property, mixed $value, array $properties, CreationContext $context): string\n    {\n        $path = $this->config()->path . $value;\n\n        if ($properties['realpath'] ?? false) {\n            return $value ?: $path;\n        }\n\n        return $this->filename($path) ?: $path;\n    }\n\n    protected function filename(string $path): false|string\n    {\n        return realpath(Str::finish($path, '.php'));\n    }\n\n    protected function config(): ConfigData\n    {\n        return app(ConfigData::class);\n    }\n}\n"
  },
  {
    "path": "src/Data/Config/ConfigData.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data\\Config;\n\nuse DragonCode\\LaravelDeployOperations\\Data\\Casts\\Config\\ExcludeCast;\nuse DragonCode\\LaravelDeployOperations\\Data\\Casts\\Config\\PathCast;\nuse Spatie\\LaravelData\\Attributes\\WithCast;\nuse Spatie\\LaravelData\\Data;\n\nclass ConfigData extends Data\n{\n    public ?string $connection;\n\n    public string $table;\n\n    #[WithCast(PathCast::class)]\n    public string $path;\n\n    #[WithCast(ExcludeCast::class)]\n    public ?array $exclude;\n\n    public bool $async;\n\n    public TransactionsData $transactions;\n\n    public QueueData $queue;\n\n    public ShowData $show;\n}\n"
  },
  {
    "path": "src/Data/Config/QueueData.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data\\Config;\n\nuse Spatie\\LaravelData\\Data;\n\nclass QueueData extends Data\n{\n    public ?string $connection;\n\n    public ?string $name;\n}\n"
  },
  {
    "path": "src/Data/Config/ShowData.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data\\Config;\n\nuse Spatie\\LaravelData\\Attributes\\MapInputName;\nuse Spatie\\LaravelData\\Data;\nuse Spatie\\LaravelData\\Mappers\\SnakeCaseMapper;\n\n#[MapInputName(SnakeCaseMapper::class)]\nclass ShowData extends Data\n{\n    public bool $fullPath;\n}\n"
  },
  {
    "path": "src/Data/Config/TransactionsData.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data\\Config;\n\nuse Spatie\\LaravelData\\Data;\n\nclass TransactionsData extends Data\n{\n    public bool $enabled;\n\n    public int $attempts;\n}\n"
  },
  {
    "path": "src/Data/OptionsData.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Data;\n\nuse DragonCode\\LaravelDeployOperations\\Data\\Casts\\BoolCast;\nuse DragonCode\\LaravelDeployOperations\\Data\\Casts\\OperationNameCast;\nuse DragonCode\\LaravelDeployOperations\\Data\\Casts\\PathCast;\nuse Spatie\\LaravelData\\Attributes\\WithCast;\nuse Spatie\\LaravelData\\Data;\n\nclass OptionsData extends Data\n{\n    #[WithCast(BoolCast::class)]\n    public bool $before = false;\n\n    public ?string $connection = null;\n\n    #[WithCast(BoolCast::class)]\n    public bool $force = false;\n\n    #[WithCast(OperationNameCast::class)]\n    public ?string $name = null;\n\n    #[WithCast(PathCast::class)]\n    public ?string $path = null;\n\n    #[WithCast(BoolCast::class)]\n    public bool $realpath = false;\n\n    public ?int $step = null;\n\n    public bool $mute = false;\n\n    public bool $sync = false;\n\n    public static function prepareForPipeline(array $properties): array\n    {\n        $properties['path'] ??= '';\n\n        return $properties;\n    }\n}\n"
  },
  {
    "path": "src/Enums/MethodEnum.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Enums;\n\nenum MethodEnum: string\n{\n    case Up   = 'up';\n    case Down = 'down';\n}\n"
  },
  {
    "path": "src/Enums/StatusEnum.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Enums;\n\nenum StatusEnum\n{\n    case Ran;\n    case Pending;\n    case Skipped;\n\n    public function toColor(): string\n    {\n        return match ($this) {\n            self::Ran     => '<fg=green;options=bold>Ran</>',\n            self::Pending => '<fg=blue;options=bold>Pending</>',\n            self::Skipped => '<fg=yellow;options=bold>Skipped</>',\n        };\n    }\n}\n"
  },
  {
    "path": "src/Events/BaseEvent.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Events;\n\nuse DragonCode\\LaravelDeployOperations\\Enums\\MethodEnum;\n\nabstract class BaseEvent\n{\n    public function __construct(\n        public MethodEnum $method,\n        public bool $before\n    ) {}\n}\n"
  },
  {
    "path": "src/Events/DeployOperationEnded.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Events;\n\nclass DeployOperationEnded extends BaseEvent {}\n"
  },
  {
    "path": "src/Events/DeployOperationFailed.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Events;\n\nclass DeployOperationFailed extends BaseEvent {}\n"
  },
  {
    "path": "src/Events/DeployOperationStarted.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Events;\n\nclass DeployOperationStarted extends BaseEvent {}\n"
  },
  {
    "path": "src/Events/NoPendingDeployOperations.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Events;\n\nclass NoPendingDeployOperations extends BaseEvent {}\n"
  },
  {
    "path": "src/Helpers/GitHelper.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Helpers;\n\nuse DragonCode\\Support\\Facades\\Filesystem\\Directory;\n\nuse function base_path;\nuse function exec;\nuse function realpath;\nuse function rtrim;\nuse function sprintf;\n\nclass GitHelper\n{\n    public function currentBranch(?string $path = null): ?string\n    {\n        if ($this->hasGitDirectory($path)) {\n            return $this->exec('rev-parse --abbrev-ref HEAD', $this->resolvePath($path));\n        }\n\n        return null;\n    }\n\n    protected function exec(string $command, ?string $path = null): ?string\n    {\n        return exec(sprintf('git -C \"%s\" %s', $path, $command));\n    }\n\n    protected function hasGitDirectory(?string $path = null): bool\n    {\n        if ($path = rtrim($this->resolvePath($path), '/\\\\')) {\n            return Directory::exists($path . DIRECTORY_SEPARATOR . '.git');\n        }\n\n        return false;\n    }\n\n    protected function resolvePath(?string $path = null): string\n    {\n        return realpath($path ?: base_path());\n    }\n}\n"
  },
  {
    "path": "src/Helpers/OperationHelper.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Helpers;\n\nuse DragonCode\\LaravelDeployOperations\\Console\\OperationsCommand;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\Artisan;\n\nclass OperationHelper\n{\n    public static function run(?string $path = null, ?bool $realpath = null): void\n    {\n        $parameters = (new Collection)\n            ->when($path, fn (Collection $items) => $items->put('--' . Options::Path, $path))\n            ->when($realpath, fn (Collection $items) => $items->put('--' . Options::Realpath, true))\n            ->all();\n\n        Artisan::call(OperationsCommand::class, $parameters);\n    }\n}\n"
  },
  {
    "path": "src/Helpers/SorterHelper.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Helpers;\n\nuse Closure;\nuse DragonCode\\Support\\Facades\\Filesystem\\Path;\nuse DragonCode\\Support\\Facades\\Helpers\\Arr;\n\nuse function in_array;\n\nclass SorterHelper\n{\n    public function byValues(array $items): array\n    {\n        return Arr::sort($items, $this->callback());\n    }\n\n    public function byKeys(array $items): array\n    {\n        return Arr::ksort($items, $this->callback());\n    }\n\n    public function byRan(array $values, array $completed): array\n    {\n        foreach ($values as $value) {\n            if (! in_array($value, $completed, true)) {\n                $completed[] = $value;\n            }\n        }\n\n        return $completed;\n    }\n\n    protected function callback(): Closure\n    {\n        return static function (string $a, string $b): int {\n            $current = Path::filename($a);\n            $next    = Path::filename($b);\n\n            if ($current === $next) {\n                return 0;\n            }\n\n            return $current < $next ? -1 : 1;\n        };\n    }\n}\n"
  },
  {
    "path": "src/Jobs/OperationJob.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Jobs;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse Illuminate\\Bus\\Queueable;\nuse Illuminate\\Contracts\\Queue\\ShouldBeUnique;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Foundation\\Bus\\Dispatchable;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Illuminate\\Support\\Facades\\Artisan;\n\nuse function app;\n\nclass OperationJob implements ShouldBeUnique, ShouldQueue\n{\n    use Dispatchable;\n    use InteractsWithQueue;\n    use Queueable;\n    use SerializesModels;\n\n    public function __construct(\n        public string $filename,\n    ) {\n        $this->onConnection($this->config()->queue->connection);\n        $this->onQueue($this->config()->queue->name);\n    }\n\n    public function handle(): void\n    {\n        Artisan::call(Names::Operations, [\n            '--' . Options::Path => $this->filename,\n            '--' . Options::Sync => true,\n        ]);\n    }\n\n    public function uniqueId(): string\n    {\n        return $this->filename;\n    }\n\n    protected function config(): ConfigData\n    {\n        return app(ConfigData::class);\n    }\n}\n"
  },
  {
    "path": "src/Listeners/Listener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Listeners;\n\nuse DragonCode\\LaravelDeployOperations\\Console\\OperationsCommand;\nuse DragonCode\\LaravelDeployOperations\\Console\\RollbackCommand;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Support\\Facades\\Artisan;\n\nuse function array_merge;\n\nabstract class Listener\n{\n    protected function withOperation(Migration $migration): ?string\n    {\n        if (method_exists($migration, 'withOperation')) {\n            return $migration->withOperation();\n        }\n\n        return null;\n    }\n\n    protected function run(string $method, string $operation): void\n    {\n        match ($method) {\n            'up'   => $this->call(OperationsCommand::class, $operation),\n            'down' => $this->call(RollbackCommand::class, $operation, ['--force' => true]),\n        };\n    }\n\n    protected function call(string $command, string $filename, array $parameters = []): void\n    {\n        Artisan::call($command, array_merge([\n            '--' . Options::Path => $filename,\n        ], $parameters));\n    }\n}\n"
  },
  {
    "path": "src/Listeners/MigrationEndedListener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Listeners;\n\nuse Illuminate\\Database\\Events\\MigrationEnded;\n\nclass MigrationEndedListener extends Listener\n{\n    public function handle(MigrationEnded $event): void\n    {\n        if ($operation = $this->withOperation($event->migration)) {\n            $this->run($event->method, $operation);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Notifications/Notification.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Notifications;\n\nuse Closure;\nuse Illuminate\\Console\\OutputStyle;\nuse Illuminate\\Console\\View\\Components\\Factory;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\nclass Notification\n{\n    protected ?OutputStyle $output = null;\n\n    protected bool $silent = false;\n\n    protected int $verbosity = OutputInterface::VERBOSITY_NORMAL;\n\n    protected ?Factory $components = null;\n\n    public function line(string $string, ?string $style = null): void\n    {\n        if ($this->canSpeak()) {\n            $this->components()->line($style, $string, $this->verbosity);\n        }\n    }\n\n    public function info(string $string): void\n    {\n        if ($this->canSpeak()) {\n            $this->components()->info($string, $this->verbosity);\n        }\n    }\n\n    public function warning(string $string): void\n    {\n        if ($this->canSpeak()) {\n            $this->components()->warn($string, $this->verbosity);\n        }\n    }\n\n    public function task(string $description, Closure $task): void\n    {\n        if ($this->canSpeak()) {\n            $this->components()->task($description, $task);\n\n            return;\n        }\n\n        $task();\n    }\n\n    public function twoColumn(string $first, string $second): void\n    {\n        if ($this->canSpeak()) {\n            $this->components()->twoColumnDetail($first, $second, $this->verbosity);\n        }\n    }\n\n    protected function components(): Factory\n    {\n        return $this->components ??= new Factory($this->output);\n    }\n\n    public function setOutput(OutputStyle $output, bool $silent = false): Notification\n    {\n        $this->output = $output;\n        $this->silent = $silent;\n\n        return $this;\n    }\n\n    protected function canSpeak(): bool\n    {\n        return ! $this->silent;\n    }\n}\n"
  },
  {
    "path": "src/Operation.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations;\n\nuse DragonCode\\LaravelDeployOperations\\Concerns\\HasArtisan;\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\n\nuse function app;\n\nabstract class Operation\n{\n    use HasArtisan;\n\n    /**\n     * Determines the type of launch of the deploy operation.\n     *\n     * If true, then it will be executed once.\n     * If false, then the operation will run every time the `operations` command is invoked.\n     */\n    public function shouldOnce(): bool\n    {\n        return true;\n    }\n\n    /** Determines a call to database transactions. */\n    public function withinTransactions(): bool\n    {\n        return app(ConfigData::class)->transactions->enabled;\n    }\n\n    /** Determines whether the given operation can be called conditionally. */\n    public function shouldRun(): bool\n    {\n        return true;\n    }\n\n    /** Defines a possible \"pre-launch\" of the operation. */\n    public function needBefore(): bool\n    {\n        return true;\n    }\n\n    /** Defines whether the operation will run synchronously or asynchronously. */\n    public function needAsync(): bool\n    {\n        return app(ConfigData::class)->async;\n    }\n\n    /** Method to be called when the job completes successfully. */\n    public function success(): void {}\n\n    /** The method will be called if an error occurs. */\n    public function failed(): void {}\n}\n"
  },
  {
    "path": "src/Processors/FreshProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Processors;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\n\nclass FreshProcessor extends Processor\n{\n    public function handle(): void\n    {\n        $this->drop();\n        $this->operations();\n    }\n\n    protected function drop(): void\n    {\n        if ($this->repository->repositoryExists()) {\n            $this->notification->task('Dropping all operations', fn () => $this->repository->deleteRepository());\n        }\n    }\n\n    protected function operations(): void\n    {\n        $this->runCommand(Names::Operations, [\n            '--' . Options::Connection => $this->options->connection,\n            '--' . Options::Path       => $this->options->path,\n            '--' . Options::Realpath   => true,\n        ]);\n    }\n}\n"
  },
  {
    "path": "src/Processors/InstallProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Processors;\n\nuse DragonCode\\Support\\Facades\\Filesystem\\Directory;\nuse DragonCode\\Support\\Facades\\Filesystem\\Path;\nuse DragonCode\\Support\\Facades\\Helpers\\Str;\n\nclass InstallProcessor extends Processor\n{\n    public function handle(): void\n    {\n        if ($this->exists()) {\n            $this->notification->info('Operations repository already exists');\n\n            return;\n        }\n\n        $this->notification->task('Installing the operation repository', function () {\n            $this->create();\n            $this->ensureDirectory();\n        });\n    }\n\n    protected function isFile(string $path): bool\n    {\n        return Str::of($path)->lower()->endsWith('.php');\n    }\n\n    protected function exists(): bool\n    {\n        return $this->repository->repositoryExists();\n    }\n\n    protected function create(): void\n    {\n        $this->repository->createRepository();\n    }\n\n    protected function ensureDirectory(): void\n    {\n        $this->isFile($this->options->path)\n            ? Directory::ensureDirectory(Path::dirname($this->options->path))\n            : Directory::ensureDirectory($this->options->path);\n    }\n}\n"
  },
  {
    "path": "src/Processors/MakeProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Processors;\n\nuse DragonCode\\Support\\Facades\\Filesystem\\File;\nuse DragonCode\\Support\\Facades\\Filesystem\\Path;\nuse DragonCode\\Support\\Facades\\Helpers\\Str;\nuse DragonCode\\Support\\Helpers\\Ables\\Stringable;\n\nuse function base_path;\nuse function date;\nuse function Laravel\\Prompts\\text;\nuse function realpath;\n\nclass MakeProcessor extends Processor\n{\n    protected string $fallback = 'auto';\n\n    protected string $defaultStub = __DIR__ . '/../../resources/stubs/deploy-operation.stub';\n\n    public function handle(): void\n    {\n        $fullPath = $this->getFullPath();\n\n        $this->notification->task($this->message($fullPath), fn () => $this->create($fullPath));\n    }\n\n    protected function message(string $path): string\n    {\n        return 'Operation [' . $this->displayName($path) . '] created successfully';\n    }\n\n    protected function create(string $path): void\n    {\n        File::copy($this->stubPath(), $path);\n    }\n\n    protected function displayName(string $path): string\n    {\n        return Str::of($path)\n            ->when(! $this->showFullPath(), fn (Stringable $str) => $str->after(base_path()))\n            ->replace('\\\\', '/')\n            ->ltrim('./')\n            ->toString();\n    }\n\n    protected function getName(): string\n    {\n        return $this->getFilename(\n            $this->getBranchName()\n        );\n    }\n\n    protected function getPath(): string\n    {\n        return $this->options->path;\n    }\n\n    protected function getFullPath(): string\n    {\n        return $this->getPath() . $this->getName();\n    }\n\n    protected function getFilename(string $branch): string\n    {\n        $directory = Path::dirname($branch);\n        $filename  = Path::filename($branch);\n\n        return Str::of($filename)\n            ->snake()\n            ->prepend($this->getTime())\n            ->finish('.php')\n            ->prepend($directory . '/')\n            ->replace('\\\\', '/')\n            ->ltrim('./')\n            ->toString();\n    }\n\n    protected function getBranchName(): string\n    {\n        if ($name = trim((string) $this->options->name)) {\n            return $name;\n        }\n\n        if ($name = $this->askForName()) {\n            return $name;\n        }\n\n        return $this->git->currentBranch() ?? $this->fallback;\n    }\n\n    protected function askForName(): string\n    {\n        $prompt = $this->promptForName();\n\n        return text($prompt[0], $prompt[1], hint: $prompt[2]);\n    }\n\n    protected function promptForName(): array\n    {\n        return ['What should the operation be named?', 'E.g. activate articles', 'Press Enter to autodetect'];\n    }\n\n    protected function getTime(): string\n    {\n        return date('Y_m_d_His_');\n    }\n\n    protected function stubPath(): string\n    {\n        if ($path = realpath(base_path('stubs/deploy-operation.stub'))) {\n            return $path;\n        }\n\n        return $this->defaultStub;\n    }\n\n    protected function showFullPath(): bool\n    {\n        return $this->config->show->fullPath;\n    }\n}\n"
  },
  {
    "path": "src/Processors/OperationsProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Processors;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\LaravelDeployOperations\\Enums\\MethodEnum;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationEnded;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationFailed;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationStarted;\nuse DragonCode\\LaravelDeployOperations\\Events\\NoPendingDeployOperations;\nuse DragonCode\\Support\\Facades\\Helpers\\Str;\nuse Throwable;\n\nclass OperationsProcessor extends Processor\n{\n    public function handle(): void\n    {\n        $this->showCaption();\n        $this->ensureRepository();\n        $this->runOperations($this->getCompleted());\n    }\n\n    protected function showCaption(): void\n    {\n        $this->notification->info('Running operations');\n    }\n\n    protected function ensureRepository(): void\n    {\n        $this->runCommand(Names::Install, [\n            '--' . Options::Connection => $this->options->connection,\n            '--' . Options::Force      => true,\n            '--' . Options::Mute       => true,\n        ]);\n    }\n\n    protected function runOperations(array $completed): void\n    {\n        try {\n            if ($files = $this->getNewFiles($completed)) {\n                $this->fireEvent(DeployOperationStarted::class, MethodEnum::Up);\n\n                $this->runEach($files, $this->getBatch());\n\n                $this->fireEvent(DeployOperationEnded::class, MethodEnum::Up);\n\n                return;\n            }\n\n            $this->fireEvent(NoPendingDeployOperations::class, MethodEnum::Up);\n        } catch (Throwable $e) {\n            $this->fireEvent(DeployOperationFailed::class, MethodEnum::Up);\n\n            throw $e;\n        }\n    }\n\n    protected function runEach(array $files, int $batch): void\n    {\n        foreach ($files as $file) {\n            $this->run($file, $batch);\n        }\n    }\n\n    protected function run(string $filename, int $batch): void\n    {\n        $this->migrator->runUp($filename, $batch, $this->options);\n    }\n\n    protected function getNewFiles(array $completed): array\n    {\n        return $this->getFiles(\n            path: $this->options->path,\n            filter: fn (string $file) => ! Str::of($file)->replace('\\\\', '/')->contains($completed)\n        );\n    }\n\n    protected function getCompleted(): array\n    {\n        return $this->repository->getCompleted()->pluck('operation')->all();\n    }\n\n    protected function getBatch(): int\n    {\n        return $this->repository->getNextBatchNumber();\n    }\n}\n"
  },
  {
    "path": "src/Processors/Processor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Processors;\n\nuse Closure;\nuse DragonCode\\LaravelDeployOperations\\Concerns\\HasArtisan;\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse DragonCode\\LaravelDeployOperations\\Data\\OptionsData;\nuse DragonCode\\LaravelDeployOperations\\Enums\\MethodEnum;\nuse DragonCode\\LaravelDeployOperations\\Helpers\\GitHelper;\nuse DragonCode\\LaravelDeployOperations\\Helpers\\SorterHelper;\nuse DragonCode\\LaravelDeployOperations\\Notifications\\Notification;\nuse DragonCode\\LaravelDeployOperations\\Repositories\\OperationsRepository;\nuse DragonCode\\LaravelDeployOperations\\Services\\MigratorService;\nuse DragonCode\\Support\\Facades\\Helpers\\Arr;\nuse DragonCode\\Support\\Facades\\Helpers\\Str;\nuse DragonCode\\Support\\Filesystem\\File;\nuse Illuminate\\Console\\OutputStyle;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\n\nuse function array_filter;\n\nabstract class Processor\n{\n    use HasArtisan;\n\n    abstract public function handle(): void;\n\n    public function __construct(\n        protected OptionsData $options,\n        protected InputInterface $input,\n        protected OutputStyle $output,\n        protected ConfigData $config,\n        protected OperationsRepository $repository,\n        protected GitHelper $git,\n        protected File $file,\n        protected MigratorService $migrator,\n        protected Notification $notification,\n        protected Dispatcher $events,\n        protected SorterHelper $sorter\n    ) {\n        $this->notification->setOutput($this->output, $this->options->mute);\n        $this->repository->setConnection($this->options->connection);\n        $this->migrator->setConnection($this->options->connection)->setOutput($this->output);\n    }\n\n    protected function getFiles(string $path, ?Closure $filter = null): array\n    {\n        $file = Str::finish($path, '.php');\n\n        $files = $this->isFile($file) ? [$file] : $this->file->names($path, $filter, true);\n\n        $files = Arr::filter(\n            $files,\n            fn (string $path) => Str::endsWith($path, '.php') && ! Str::contains($path, $this->config->exclude)\n        );\n\n        return Arr::of($this->sorter->byValues($files))\n            ->map(fn (string $value) => Str::before($value, '.php'))\n            ->toArray();\n    }\n\n    protected function runCommand(string $command, array $options = []): void\n    {\n        $this->artisan($command, array_filter($options), $this->output);\n    }\n\n    protected function tableNotFound(): bool\n    {\n        if (! $this->repository->repositoryExists()) {\n            $this->notification->warning('Deploy operations table not found');\n\n            return true;\n        }\n\n        return false;\n    }\n\n    protected function fireEvent(string $event, MethodEnum $method): void\n    {\n        $this->events->dispatch(new $event($method, $this->options->before));\n    }\n\n    protected function isFile(string $path): bool\n    {\n        return $this->file->exists($path) && $this->file->isFile($path);\n    }\n}\n"
  },
  {
    "path": "src/Processors/RollbackProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Processors;\n\nuse DragonCode\\LaravelDeployOperations\\Enums\\MethodEnum;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationEnded;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationStarted;\nuse DragonCode\\LaravelDeployOperations\\Events\\NoPendingDeployOperations;\n\nclass RollbackProcessor extends Processor\n{\n    public function handle(): void\n    {\n        if ($this->tableNotFound() || $this->nothingToRollback()) {\n            $this->fireEvent(NoPendingDeployOperations::class, MethodEnum::Down);\n\n            return;\n        }\n\n        if ($items = $this->getOperations($this->options->step)) {\n            $this->fireEvent(DeployOperationStarted::class, MethodEnum::Down);\n\n            $this->showCaption();\n            $this->run($items);\n\n            $this->fireEvent(DeployOperationEnded::class, MethodEnum::Down);\n\n            return;\n        }\n\n        $this->fireEvent(NoPendingDeployOperations::class, MethodEnum::Down);\n    }\n\n    protected function showCaption(): void\n    {\n        $this->notification->info('Rollback Operations');\n    }\n\n    protected function run(array $rows): void\n    {\n        foreach ($rows as $row) {\n            $this->rollback($row->operation);\n        }\n    }\n\n    protected function getOperations(?int $step): array\n    {\n        return (int) $step > 0\n            ? $this->repository->getByStep($step)\n            : $this->repository->getLast();\n    }\n\n    protected function rollback(string $item): void\n    {\n        $this->migrator->runDown($item, $this->options);\n    }\n\n    protected function nothingToRollback(): bool\n    {\n        if ($this->count() <= 0) {\n            $this->notification->info('Nothing To Rollback');\n\n            return true;\n        }\n\n        return false;\n    }\n\n    protected function count(): int\n    {\n        return $this->repository->getLastBatchNumber();\n    }\n}\n"
  },
  {
    "path": "src/Processors/StatusProcessor.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Processors;\n\nuse DragonCode\\LaravelDeployOperations\\Enums\\StatusEnum;\nuse DragonCode\\Support\\Facades\\Helpers\\Arr;\n\nuse function sprintf;\n\nclass StatusProcessor extends Processor\n{\n    protected string $columnName = '<fg=gray>Operation name</>';\n\n    protected string $columnStatus = '<fg=gray>Batch / Status</>';\n\n    public function handle(): void\n    {\n        if ($this->tableNotFound()) {\n            return;\n        }\n\n        [$files, $completed] = $this->getData();\n\n        if ($this->isEmpty($files, $completed)) {\n            $this->notification->info('No operations found');\n\n            return;\n        }\n\n        $this->showCaption();\n        $this->showHeaders();\n        $this->showStatus($files, $completed);\n    }\n\n    protected function showCaption(): void\n    {\n        $this->notification->info('Show Status');\n    }\n\n    protected function showHeaders(): void\n    {\n        $this->notification->twoColumn($this->columnName, $this->columnStatus);\n    }\n\n    protected function showStatus(array $items, array $completed): void\n    {\n        foreach ($this->merge($items, array_keys($completed)) as $item) {\n            $status = $this->getStatusFor($completed, $item);\n\n            $this->notification->twoColumn($item, $status);\n        }\n    }\n\n    protected function merge(array $items, array $completed): array\n    {\n        return $this->sorter->byRan($items, $completed);\n    }\n\n    protected function getData(): array\n    {\n        $files     = $this->getFiles($this->options->path);\n        $completed = $this->getCompleted();\n\n        return [$files, $completed];\n    }\n\n    protected function getStatusFor(array $completed, string $item): string\n    {\n        if ($batch = Arr::get($completed, $item)) {\n            return sprintf('[%s] %s', $batch, StatusEnum::Ran->toColor());\n        }\n\n        return StatusEnum::Pending->toColor();\n    }\n\n    protected function getCompleted(): array\n    {\n        return $this->repository->getCompleted()\n            ->pluck('batch', 'operation')\n            ->all();\n    }\n\n    protected function isEmpty(array $items, array $completed): bool\n    {\n        return empty($items) && empty($completed);\n    }\n}\n"
  },
  {
    "path": "src/Repositories/OperationsRepository.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Repositories;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Order;\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse Illuminate\\Database\\ConnectionInterface;\nuse Illuminate\\Database\\ConnectionResolverInterface as Resolver;\nuse Illuminate\\Database\\Query\\Builder as Query;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Database\\Schema\\Builder;\nuse Illuminate\\Support\\Collection;\n\nuse function compact;\n\nclass OperationsRepository\n{\n    protected ?string $connection = null;\n\n    public function __construct(\n        protected Resolver $resolver,\n        protected ConfigData $config,\n    ) {}\n\n    public function getCompleted(): Collection\n    {\n        return $this->sortedTable()->get();\n    }\n\n    public function getByStep(int $steps): array\n    {\n        return $this->sortedTable(Order::Desc)\n            ->whereIn('batch', $this->getBatchNumbers($steps))\n            ->get()\n            ->all();\n    }\n\n    public function getLast(): array\n    {\n        return $this->sortedTable(Order::Desc)\n            ->where('batch', $this->getLastBatchNumber())\n            ->get()\n            ->all();\n    }\n\n    public function getNextBatchNumber(): int\n    {\n        return $this->getLastBatchNumber() + 1;\n    }\n\n    public function getLastBatchNumber(): int\n    {\n        return (int) $this->table()->max('batch');\n    }\n\n    public function log(string $operation, int $batch): void\n    {\n        $this->table()->insert(compact('operation', 'batch'));\n    }\n\n    public function delete(string $operation): void\n    {\n        $this->table()->where(compact('operation'))->delete();\n    }\n\n    public function createRepository(): void\n    {\n        $this->schema()->create($this->config->table, function (Blueprint $table) {\n            $table->bigIncrements('id');\n\n            $table->string('operation');\n\n            $table->unsignedInteger('batch');\n        });\n    }\n\n    public function repositoryExists(): bool\n    {\n        return $this->schema()->hasTable($this->config->table);\n    }\n\n    public function deleteRepository(): void\n    {\n        $this->schema()->dropIfExists($this->config->table);\n    }\n\n    /** @return array<int> */\n    protected function getBatchNumbers(int $steps): array\n    {\n        return $this->sortedTable(Order::Desc)\n            ->pluck('batch')\n            ->unique()\n            ->take($steps)\n            ->all();\n    }\n\n    protected function sortedTable(string $order = Order::Asc): Query\n    {\n        return $this->table()\n            ->orderBy('batch', $order)\n            ->orderBy('id', $order);\n    }\n\n    protected function schema(): Builder\n    {\n        return $this->getConnection()->getSchemaBuilder();\n    }\n\n    protected function table(): Query\n    {\n        return $this->getConnection()->table($this->config->table)->useWritePdo();\n    }\n\n    protected function getConnection(): ConnectionInterface\n    {\n        return $this->resolver->connection(\n            $this->connection ?: $this->config->connection\n        );\n    }\n\n    public function setConnection(?string $connection): self\n    {\n        $this->connection = $connection;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/ServiceProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations;\n\nuse DragonCode\\LaravelDeployOperations\\Concerns\\HasAbout;\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse DragonCode\\LaravelDeployOperations\\Listeners\\MigrationEndedListener;\nuse Illuminate\\Database\\Events\\MigrationEnded;\nuse Illuminate\\Support\\Facades\\Event;\nuse Illuminate\\Support\\ServiceProvider as BaseServiceProvider;\n\nuse function config;\n\nclass ServiceProvider extends BaseServiceProvider\n{\n    use HasAbout;\n\n    public function boot(): void\n    {\n        $this->registerEvents();\n        $this->bootConfig();\n\n        if ($this->app->runningInConsole()) {\n            $this->publishConfig();\n            $this->publishStub();\n\n            $this->registerAbout();\n            $this->registerCommands();\n            $this->registerMigrations();\n        }\n    }\n\n    public function register(): void\n    {\n        $this->registerConfig();\n    }\n\n    protected function registerCommands(): void\n    {\n        $this->commands([\n            Console\\OperationsCommand::class,\n            Console\\FreshCommand::class,\n            Console\\InstallCommand::class,\n            Console\\MakeCommand::class,\n            Console\\RollbackCommand::class,\n            Console\\StatusCommand::class,\n        ]);\n    }\n\n    protected function registerEvents(): void\n    {\n        Event::listen(MigrationEnded::class, MigrationEndedListener::class);\n    }\n\n    protected function registerMigrations(): void\n    {\n        $this->loadMigrationsFrom(__DIR__ . '/../database/migrations');\n    }\n\n    protected function publishConfig(): void\n    {\n        $this->publishes([\n            __DIR__ . '/../config/deploy-operations.php' => $this->app->configPath('deploy-operations.php'),\n        ], ['config', 'deploy-operations']);\n    }\n\n    protected function publishStub(): void\n    {\n        $this->publishes([\n            __DIR__ . '/../resources/stubs/deploy-operation.stub' => $this->app->basePath(\n                'stubs/deploy-operation.stub'\n            ),\n        ], ['stubs', 'deploy-operations']);\n    }\n\n    protected function registerConfig(): void\n    {\n        $this->mergeConfigFrom(__DIR__ . '/../config/deploy-operations.php', 'deploy-operations');\n    }\n\n    protected function bootConfig(): void\n    {\n        $this->app->bind(ConfigData::class, static fn () => ConfigData::from(\n            config('deploy-operations')\n        ));\n    }\n}\n"
  },
  {
    "path": "src/Services/MigratorService.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Services;\n\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse DragonCode\\LaravelDeployOperations\\Data\\OptionsData;\nuse DragonCode\\LaravelDeployOperations\\Enums\\StatusEnum;\nuse DragonCode\\LaravelDeployOperations\\Jobs\\OperationJob;\nuse DragonCode\\LaravelDeployOperations\\Notifications\\Notification;\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse DragonCode\\LaravelDeployOperations\\Repositories\\OperationsRepository;\nuse DragonCode\\Support\\Exceptions\\FileNotFoundException;\nuse DragonCode\\Support\\Facades\\Helpers\\Str;\nuse DragonCode\\Support\\Filesystem\\File;\nuse Illuminate\\Console\\OutputStyle;\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Support\\Facades\\DB;\nuse Throwable;\n\nuse function file_exists;\nuse function is_file;\nuse function method_exists;\nuse function realpath;\n\nclass MigratorService\n{\n    public function __construct(\n        protected File $file,\n        protected Notification $notification,\n        protected OperationsRepository $repository,\n        protected ConfigData $config,\n        protected Container $container\n    ) {}\n\n    public function setConnection(?string $connection): self\n    {\n        $this->repository->setConnection($connection);\n\n        return $this;\n    }\n\n    public function setOutput(OutputStyle $output): self\n    {\n        $this->notification->setOutput($output);\n\n        return $this;\n    }\n\n    public function runUp(string $filename, int $batch, OptionsData $options): void\n    {\n        $path      = $this->resolvePath($filename, $options->path);\n        $operation = $this->resolveOperation($path);\n        $name      = $this->resolveOperationName($path);\n\n        if (! $this->allowOperation($operation, $options)) {\n            $this->notification->twoColumn($name, StatusEnum::Skipped->toColor());\n\n            return;\n        }\n\n        if ($this->needAsync($operation, $options)) {\n            OperationJob::dispatch($name);\n\n            $this->notification->twoColumn($name, StatusEnum::Pending->toColor());\n\n            return;\n        }\n\n        $this->notification->task($name, function () use ($operation, $name, $batch) {\n            $this->hasMethod($operation, '__invoke')\n                ? $this->runOperation($operation, '__invoke')\n                : $this->runOperation($operation, 'up');\n\n            if ($operation->shouldOnce()) {\n                $this->log($name, $batch);\n            }\n        });\n    }\n\n    public function runDown(string $filename, OptionsData $options): void\n    {\n        $path      = $this->resolvePath($filename, $options->path);\n        $operation = $this->resolveOperation($path);\n        $name      = $this->resolveOperationName($path);\n\n        $this->notification->task($name, function () use ($operation, $name) {\n            $this->runOperation($operation, 'down');\n            $this->deleteLog($name);\n        });\n    }\n\n    protected function runOperation(Operation $operation, string $method): void\n    {\n        if ($this->hasMethod($operation, $method)) {\n            try {\n                $this->runMethod($operation, $method, $operation->withinTransactions());\n\n                $operation->success();\n            } catch (Throwable $e) {\n                $operation->failed();\n\n                throw $e;\n            }\n        }\n    }\n\n    protected function hasMethod(Operation $operation, string $method): bool\n    {\n        return method_exists($operation, $method);\n    }\n\n    protected function needAsync(Operation $operation, OptionsData $options): bool\n    {\n        return ! $options->sync && $operation->needAsync();\n    }\n\n    protected function runMethod(Operation $operation, string $method, bool $transactions): void\n    {\n        $callback = fn () => $this->container->call([$operation, $method]);\n\n        $transactions ? DB::transaction($callback, $this->config->transactions->attempts) : $callback();\n    }\n\n    protected function log(string $name, int $batch): void\n    {\n        $this->repository->log($name, $batch);\n    }\n\n    protected function deleteLog(string $name): void\n    {\n        $this->repository->delete($name);\n    }\n\n    protected function allowOperation(Operation $operation, OptionsData $options): bool\n    {\n        if (! $operation->shouldRun()) {\n            return false;\n        }\n\n        return ! $this->disallowBefore($operation, $options);\n    }\n\n    protected function disallowBefore(Operation $operation, OptionsData $options): bool\n    {\n        return $options->before && ! $operation->needBefore();\n    }\n\n    protected function resolvePath(string $filename, string $path): string\n    {\n        if (file_exists($path) && is_file($path)) {\n            return $path;\n        }\n\n        $withExtension = Str::finish($filename, '.php');\n\n        if ($this->file->exists($withExtension) && $this->file->isFile($withExtension)) {\n            return $withExtension;\n        }\n\n        return Str::finish($path . DIRECTORY_SEPARATOR . $filename, '.php');\n    }\n\n    protected function resolveOperation(string $path): Operation\n    {\n        if ($this->file->exists($path)) {\n            return require $path;\n        }\n\n        throw new FileNotFoundException($path);\n    }\n\n    protected function resolveOperationName(string $path): string\n    {\n        return Str::of(realpath($path))\n            ->after(realpath($this->config->path) . DIRECTORY_SEPARATOR)\n            ->replace(['\\\\', '/'], '/')\n            ->before('.php')\n            ->toString();\n    }\n}\n"
  },
  {
    "path": "src/Services/MutexService.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations\\Services;\n\nuse Carbon\\CarbonInterval;\nuse DragonCode\\LaravelDeployOperations\\Console\\Command;\nuse Illuminate\\Contracts\\Cache\\Factory;\nuse Illuminate\\Contracts\\Cache\\Repository;\n\nclass MutexService\n{\n    protected ?string $store = null;\n\n    public function __construct(\n        protected Factory $cache\n    ) {}\n\n    public function create(Command $command): bool\n    {\n        return $this->store()->add($this->name($command), true, $this->ttl());\n    }\n\n    public function forget(Command $command): void\n    {\n        $this->store()->forget(\n            $this->name($command)\n        );\n    }\n\n    protected function store(): Repository\n    {\n        return $this->cache->store($this->store);\n    }\n\n    protected function ttl(): CarbonInterval\n    {\n        return CarbonInterval::hour();\n    }\n\n    protected function name(Command $command): string\n    {\n        return 'framework' . DIRECTORY_SEPARATOR . 'deploy-operation-' . $command->getName();\n    }\n}\n"
  },
  {
    "path": "src/helpers.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DragonCode\\LaravelDeployOperations;\n\nif (! function_exists('\\DragonCode\\LaravelDeployOperations\\operation')) {\n    function operation(string $filename): string\n    {\n        return $filename;\n    }\n}\n"
  },
  {
    "path": "tests/Commands/EventsTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Commands;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationEnded;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationFailed;\nuse DragonCode\\LaravelDeployOperations\\Events\\DeployOperationStarted;\nuse Exception;\nuse Illuminate\\Support\\Facades\\Event;\nuse Tests\\TestCase;\nuse Throwable;\n\nclass EventsTest extends TestCase\n{\n    public function testSuccess(): void\n    {\n        $this->copyFiles();\n\n        Event::fake();\n\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        Event::assertDispatchedTimes(DeployOperationStarted::class, 1);\n        Event::assertDispatchedTimes(DeployOperationEnded::class, 1);\n\n        Event::assertNotDispatched(DeployOperationFailed::class);\n    }\n\n    public function testFailed(): void\n    {\n        $this->expectException(Exception::class);\n        $this->expectExceptionMessage('Custom exception');\n\n        $this->copyFailedMethod();\n\n        Event::fake();\n\n        try {\n            $this->artisan(Names::Operations)->run();\n        } catch (Throwable $e) {\n            Event::assertDispatchedTimes(DeployOperationStarted::class, 1);\n            Event::assertDispatchedTimes(DeployOperationFailed::class, 1);\n\n            Event::assertNotDispatched(DeployOperationEnded::class);\n\n            throw $e;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/Commands/FreshTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Commands;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse Tests\\TestCase;\n\nclass FreshTest extends TestCase\n{\n    public function testFreshCommand(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 0);\n\n        $this->artisan(Names::Make, ['name' => 'Fresh'])->assertExitCode(0);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 1);\n\n        $this->artisan(Names::Fresh)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, 'fresh');\n    }\n}\n"
  },
  {
    "path": "tests/Commands/InstallTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Commands;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse Tests\\TestCase;\n\nclass InstallTest extends TestCase\n{\n    public function testCreate(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n    }\n\n    public function testAlreadyCreated(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n    }\n\n    public function testMutedCreate(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install, ['--' . Options::Mute => true])->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n    }\n\n    public function testMutedAlreadyCreated(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install, ['--' . Options::Mute => true])->assertExitCode(0);\n        $this->artisan(Names::Install, ['--' . Options::Mute => true])->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n    }\n}\n"
  },
  {
    "path": "tests/Commands/MakeTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Commands;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\Support\\Facades\\Filesystem\\File;\nuse Tests\\TestCase;\n\nclass MakeTest extends TestCase\n{\n    public function testMakingFiles(): void\n    {\n        $name = 'MakeExample';\n\n        $path = $this->getOperationsPath() . '/' . date('Y_m_d_His') . '_make_example.php';\n\n        $this->assertFileDoesNotExist($path);\n\n        $this->artisan(Names::Make, compact('name'))->assertExitCode(0);\n\n        $this->assertFileExists($path);\n\n        $this->assertEquals(\n            file_get_contents(__DIR__ . '/../fixtures/app/stubs/make_example.stub'),\n            file_get_contents($path)\n        );\n    }\n\n    public function testAskedName(): void\n    {\n        $path = $this->getOperationsPath() . '/' . date('Y_m_d_His') . '_some_name.php';\n\n        $this->assertFileDoesNotExist($path);\n\n        $this->artisan(Names::Make)\n            ->expectsQuestion('What should the operation be named?', 'Some Name')\n            ->assertExitCode(0);\n\n        $this->assertFileExists($path);\n    }\n\n    public function testAutoName(): void\n    {\n        $path = $this->getOperationsPath() . '/' . date('Y_m_d_His') . '_auto.php';\n\n        $this->assertFileDoesNotExist($path);\n\n        $this->artisan(Names::Make)\n            ->expectsQuestion('What should the operation be named?', '')\n            ->assertExitCode(0);\n\n        $this->assertFileExists($path);\n    }\n\n    public function testNestedRightSlashWithoutExtension(): void\n    {\n        $name = 'Foo/bar/QweRty';\n\n        $path = $this->getOperationsPath() . '/foo/bar/' . date('Y_m_d_His') . '_qwe_rty.php';\n\n        $this->assertFileDoesNotExist($path);\n\n        $this->artisan(Names::Make, compact('name'))->assertExitCode(0);\n\n        $this->assertFileExists($path);\n\n        $this->assertEquals(\n            file_get_contents(__DIR__ . '/../fixtures/app/stubs/make_example.stub'),\n            file_get_contents($path)\n        );\n    }\n\n    public function testNestedRightSlashWithExtension(): void\n    {\n        $name = 'Foo/bar/QweRty.php';\n\n        $path = $this->getOperationsPath() . '/foo/bar/' . date('Y_m_d_His') . '_qwe_rty.php';\n\n        $this->assertFileDoesNotExist($path);\n\n        $this->artisan(Names::Make, compact('name'))->assertExitCode(0);\n\n        $this->assertFileExists($path);\n\n        $this->assertEquals(\n            file_get_contents(__DIR__ . '/../fixtures/app/stubs/make_example.stub'),\n            file_get_contents($path)\n        );\n    }\n\n    public function testNestedLeftSlashWithoutExtension(): void\n    {\n        $name = 'Foo\\\\bar\\\\QweRty';\n\n        $path = $this->getOperationsPath() . '/foo/bar/' . date('Y_m_d_His') . '_qwe_rty.php';\n\n        $this->assertFileDoesNotExist($path);\n\n        $this->artisan(Names::Make, compact('name'))->assertExitCode(0);\n\n        $this->assertFileExists($path);\n\n        $this->assertEquals(\n            file_get_contents(__DIR__ . '/../fixtures/app/stubs/make_example.stub'),\n            file_get_contents($path)\n        );\n    }\n\n    public function testNestedLeftSlashWithExtension(): void\n    {\n        $name = 'Foo\\\\bar\\\\QweRty.php';\n\n        $path = $this->getOperationsPath() . '/foo/bar/' . date('Y_m_d_His') . '_qwe_rty.php';\n\n        $this->assertFileDoesNotExist($path);\n\n        $this->artisan(Names::Make, compact('name'))->assertExitCode(0);\n\n        $this->assertFileExists($path);\n\n        $this->assertEquals(\n            file_get_contents(__DIR__ . '/../fixtures/app/stubs/make_example.stub'),\n            file_get_contents($path)\n        );\n    }\n\n    public function testFromCustomizedStub(): void\n    {\n        $name = 'MakeExample';\n\n        $stubPath = base_path('stubs/deploy-operation.stub');\n\n        $operationPath = $this->getOperationsPath() . '/' . date('Y_m_d_His') . '_make_example.php';\n\n        $this->assertFileDoesNotExist($stubPath);\n\n        File::copy(__DIR__ . '/../fixtures/app/stubs/customized.stub', $stubPath);\n\n        $this->assertFileExists($stubPath);\n        $this->assertFileDoesNotExist($operationPath);\n\n        $this->artisan(Names::Make, compact('name'))->assertExitCode(0);\n\n        $this->assertFileExists($operationPath);\n\n        $content = file_get_contents($operationPath);\n\n        $this->assertStringContainsString('Foo\\\\Bar\\\\Some', $content);\n        $this->assertStringContainsString('extends Some', $content);\n\n        $this->assertStringNotContainsString('DragonCode\\\\LaravelDeployOperations\\\\Operation', $content);\n        $this->assertStringNotContainsString('extends Operation', $content);\n    }\n}\n"
  },
  {
    "path": "tests/Commands/MutexTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Commands;\n\nuse DragonCode\\LaravelDeployOperations\\Console\\Command;\nuse DragonCode\\LaravelDeployOperations\\Constants\\Options;\nuse DragonCode\\LaravelDeployOperations\\Services\\MutexService;\nuse Illuminate\\Container\\Container;\nuse Mockery as m;\nuse Symfony\\Component\\Console\\Input\\ArrayInput;\nuse Symfony\\Component\\Console\\Output\\NullOutput;\nuse Tests\\TestCase;\n\nclass MutexTest extends TestCase\n{\n    protected Command $command;\n\n    protected MutexService $mutex;\n\n    protected function setUp(): void\n    {\n        $this->command = new class extends Command {\n            public int $ran = 0;\n\n            public function handle(): int\n            {\n                $this->ran++;\n\n                return self::SUCCESS;\n            }\n        };\n\n        $this->mutex = m::mock(MutexService::class);\n\n        $container = Container::getInstance();\n        $container->instance(MutexService::class, $this->mutex);\n        $this->command->setLaravel($container);\n    }\n\n    public function testCanRunIsolatedCommandIfNotBlocked(): void\n    {\n        $this->mutex->shouldReceive('create')\n            ->andReturn(true)\n            ->once();\n\n        $this->mutex->shouldReceive('forget')\n            ->once();\n\n        $this->runCommand();\n\n        $this->assertSame(1, $this->command->ran);\n    }\n\n    public function testCannotRunIsolatedCommandIfBlocked(): void\n    {\n        $this->mutex->shouldReceive('create')\n            ->andReturn(false)\n            ->once();\n\n        $this->mutex->shouldReceive('forget')\n            ->never();\n\n        $this->runCommand();\n\n        $this->assertSame(0, $this->command->ran);\n    }\n\n    public function testCanRunCommandAgainAfterOtherCommandFinished(): void\n    {\n        $this->mutex->shouldReceive('create')\n            ->andReturn(true)\n            ->twice();\n\n        $this->mutex->shouldReceive('forget')\n            ->twice();\n\n        $this->runCommand();\n        $this->runCommand();\n\n        $this->assertEquals(2, $this->command->ran);\n    }\n\n    public function testCanRunCommandAgainNonAutomated(): void\n    {\n        $this->mutex->shouldNotHaveBeenCalled();\n\n        $this->runCommand(false);\n\n        $this->assertEquals(1, $this->command->ran);\n    }\n\n    protected function runCommand($withIsolated = true)\n    {\n        $input  = new ArrayInput(['--' . Options::Isolated => $withIsolated]);\n        $output = new NullOutput;\n\n        $this->command->run($input, $output);\n    }\n}\n"
  },
  {
    "path": "tests/Commands/OperationsTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Commands;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Data\\Config\\ConfigData;\nuse DragonCode\\LaravelDeployOperations\\Jobs\\OperationJob;\nuse Exception;\nuse Illuminate\\Database\\Console\\Migrations\\RollbackCommand;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Queue;\nuse Illuminate\\Support\\Str;\nuse Tests\\TestCase;\nuse Throwable;\n\nclass OperationsTest extends TestCase\n{\n    public function testSuccess(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 0);\n\n        $this->artisan(Names::Make, ['name' => 'TestMigration'])->assertExitCode(0);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, 'test_migration');\n    }\n\n    public function testSameName(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 0);\n\n        $this->artisan(Names::Make, ['name' => 'TestMigration'])->assertExitCode(0);\n\n        sleep(2);\n\n        $this->artisan(Names::Make, ['name' => 'TestMigration'])->assertExitCode(0);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($this->table, 2);\n        $this->assertDatabaseOperationHas($this->table, 'test_migration');\n    }\n\n    public function testOnce(): void\n    {\n        $this->copyFiles();\n\n        $table = 'every_time';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 3);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 4);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n    }\n\n    public function testSuccessTransaction(): void\n    {\n        $this->copySuccessTransaction();\n\n        $table = 'transactions';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 3);\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, $table);\n    }\n\n    public function testFailedTransaction(): void\n    {\n        $this->copyFailedTransaction();\n\n        $table = 'transactions';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n\n        try {\n            $this->artisan(Names::Operations)->assertExitCode(0);\n        } catch (Exception $e) {\n            $this->assertSame(Exception::class, get_class($e));\n            $this->assertSame('Random message', $e->getMessage());\n        }\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n    }\n\n    public function testSingleEnvironment(): void\n    {\n        $this->copyFiles();\n\n        $table = 'environment';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_all');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_testing');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_testing');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 5);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_on_all');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_production');\n        $this->assertDatabaseOperationHas($this->table, 'run_on_testing');\n        $this->assertDatabaseOperationHas($this->table, 'run_except_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_testing');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 5);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_on_all');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_production');\n        $this->assertDatabaseOperationHas($this->table, 'run_on_testing');\n        $this->assertDatabaseOperationHas($this->table, 'run_except_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_testing');\n    }\n\n    public function testManyEnvironments(): void\n    {\n        $this->copyFiles();\n\n        $table = 'environment';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_all');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_testing');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_many_environments');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_testing');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_many_environments');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 5);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_on_all');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_production');\n        $this->assertDatabaseOperationHas($this->table, 'run_on_testing');\n        $this->assertDatabaseOperationHas($this->table, 'run_on_many_environments');\n        $this->assertDatabaseOperationHas($this->table, 'run_except_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_testing');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_many_environments');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 5);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_on_all');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_production');\n        $this->assertDatabaseOperationHas($this->table, 'run_on_testing');\n        $this->assertDatabaseOperationHas($this->table, 'run_on_many_environments');\n        $this->assertDatabaseOperationHas($this->table, 'run_except_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_testing');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_except_many_environments');\n    }\n\n    public function testAllow(): void\n    {\n        $this->copyFiles();\n\n        $table = 'environment';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_allow');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_disallow');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 5);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_allow');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_disallow');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 5);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_allow');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_disallow');\n    }\n\n    public function testUpSuccess(): void\n    {\n        $this->copyFiles();\n\n        $table = 'success';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_success');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_success');\n    }\n\n    public function testUpSuccessOnFailed(): void\n    {\n        $this->copyFiles();\n\n        $table = 'success';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_success_on_failed');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_success_on_failed');\n\n        try {\n            $this->copySuccessFailureMethod();\n\n            $this->artisan(Names::Operations)->assertExitCode(0);\n        } catch (Throwable $e) {\n            $this->assertInstanceOf(Exception::class, $e);\n\n            $this->assertSame('Custom exception', $e->getMessage());\n\n            $this->assertTrue(Str::contains($e->getFile(), 'run_success_on_failed'));\n        }\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_success_on_failed');\n    }\n\n    public function testUpFailed(): void\n    {\n        $this->copyFiles();\n\n        $table = 'failed';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_failed');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_failed');\n    }\n\n    public function testUpFailedOnException(): void\n    {\n        $this->copyFiles();\n\n        $table = 'failed';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_failed_failure');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_failed_failure');\n\n        try {\n            $this->copyFailedMethod();\n\n            $this->artisan(Names::Operations)->assertExitCode(0);\n        } catch (Throwable $e) {\n            $this->assertInstanceOf(Exception::class, $e);\n\n            $this->assertSame('Custom exception', $e->getMessage());\n\n            $this->assertTrue(Str::contains($e->getFile(), 'run_failed_failure'));\n        }\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_failed_failure');\n    }\n\n    public function testPathAsFileWithExtension(): void\n    {\n        $this->copyFiles();\n\n        $table = 'test';\n\n        $path = 'sub_path/2021_12_15_205804_baz.php';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'baz');\n        $this->artisan(Names::Operations, ['--path' => $path])->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, 'baz');\n\n        $this->assertSame('sub_path/2021_12_15_205804_baz', $this->table()->first()->operation);\n    }\n\n    public function testPathAsFileWithoutExtension(): void\n    {\n        $this->copyFiles();\n\n        $table = 'test';\n\n        $path = 'sub_path/2021_12_15_205804_baz';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'baz');\n        $this->artisan(Names::Operations, ['--path' => $path])->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, 'baz');\n\n        $this->assertSame($path, $this->table()->first()->operation);\n    }\n\n    public function testPathAsDirectory(): void\n    {\n        $this->copyFiles();\n\n        $table = 'test';\n\n        $path = 'sub_path';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'baz');\n        $this->artisan(Names::Operations, ['--path' => $path])->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 2);\n        $this->assertDatabaseOperationHas($this->table, 'baz');\n\n        $this->assertSame('sub_path/2021_12_15_205804_baz', $this->table()->first()->operation);\n    }\n\n    public function testOperationsNotFound(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n\n        $this->artisan(Names::Status)->assertExitCode(0);\n    }\n\n    public function testDisabledBefore(): void\n    {\n        $this->copyFiles();\n\n        $table = 'before';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationHas($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationHas($this->table, 'test_before_disabled');\n    }\n\n    public function testEnabledBefore(): void\n    {\n        $this->copyFiles();\n\n        $table = 'before';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations, ['--before' => true])->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 11);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations, ['--before' => true])->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 11);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n    }\n\n    public function testMixedBefore(): void\n    {\n        $this->copyFiles();\n\n        $table = 'before';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations, ['--before' => true])->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 11);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations, ['--before' => true])->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 11);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationHas($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationHas($this->table, 'test_before_disabled');\n    }\n\n    public function testDI(): void\n    {\n        $this->copyDI();\n\n        $table = 'test';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'invoke');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'invoke_down');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'up_down');\n        $this->assertDatabaseOperationDoesntLike($table, 'up_down', column: 'value');\n        $this->assertDatabaseOperationDoesntLike($table, 'invoke_down', column: 'value');\n        $this->assertDatabaseOperationDoesntLike($table, 'invoke', column: 'value');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 3);\n        $this->assertDatabaseCount($this->table, 3);\n        $this->assertDatabaseOperationHas($this->table, 'invoke');\n        $this->assertDatabaseOperationHas($this->table, 'invoke_down');\n        $this->assertDatabaseOperationHas($this->table, 'up_down');\n        $this->assertDatabaseOperationHas($table, 'up_down', column: 'value');\n        $this->assertDatabaseOperationHas($table, 'invoke_down', column: 'value');\n        $this->assertDatabaseOperationHas($table, 'invoke', column: 'value');\n    }\n\n    public function testSorting(): void\n    {\n        $files = [];\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $files[] = date('Y_m_d_His_') . 'test1';\n        $this->artisan(Names::Make, ['name' => 'test1'])->assertExitCode(0);\n        sleep(2);\n        $files[] = 'foo/' . date('Y_m_d_His_') . 'test2';\n        $this->artisan(Names::Make, ['name' => 'foo/test2'])->assertExitCode(0);\n        sleep(2);\n        $files[] = 'bar/' . date('Y_m_d_His_') . 'test3';\n        $this->artisan(Names::Make, ['name' => 'bar/test3'])->assertExitCode(0);\n        sleep(2);\n        $files[] = 'foo/' . date('Y_m_d_His_') . 'test4';\n        $this->artisan(Names::Make, ['name' => 'foo/test4'])->assertExitCode(0);\n        sleep(2);\n        $files[] = 'bar/' . date('Y_m_d_His_') . 'test5';\n        $this->artisan(Names::Make, ['name' => 'bar/test5'])->assertExitCode(0);\n        sleep(2);\n        $files[] = date('Y_m_d_His_') . 'test6';\n        $this->artisan(Names::Make, ['name' => 'test6'])->assertExitCode(0);\n\n        $this->artisan(Names::Operations)->assertExitCode(0);\n        $this->assertDatabaseCount($this->table, 6);\n\n        $records = DB::table($this->table)->orderBy('id')->pluck('operation')->all();\n\n        $this->assertSame($files, $records);\n    }\n\n    public function testDirectoryExclusion(): void\n    {\n        $this->copyFiles();\n\n        $this->app['config']->set('deploy-operations.exclude', 'sub_path');\n\n        $this->app->forgetInstance(ConfigData::class);\n\n        $table = 'every_time';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2022_10_27_230732_foo');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 10);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2022_10_27_230732_foo');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 10);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2022_10_27_230732_foo');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 3);\n        $this->assertDatabaseCount($this->table, 10);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2022_10_27_230732_foo');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 4);\n        $this->assertDatabaseCount($this->table, 10);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2022_10_27_230732_foo');\n    }\n\n    public function testFileExclusion(): void\n    {\n        $this->copyFiles();\n\n        $this->app['config']->set('deploy-operations.exclude', 'sub_path/2021_12_15_205804_baz');\n\n        $this->app->forgetInstance(ConfigData::class);\n\n        $table = 'every_time';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2022_10_27_230732_foo');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 11);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationHas($this->table, 'sub_path/2022_10_27_230732_foo');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 11);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationHas($this->table, 'sub_path/2022_10_27_230732_foo');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 3);\n        $this->assertDatabaseCount($this->table, 11);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationHas($this->table, 'sub_path/2022_10_27_230732_foo');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 4);\n        $this->assertDatabaseCount($this->table, 11);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'sub_path/2021_12_15_205804_baz');\n        $this->assertDatabaseOperationHas($this->table, 'sub_path/2022_10_27_230732_foo');\n    }\n\n    public function testEmptyDirectory(): void\n    {\n        $this->copyEmptyDirectory();\n\n        $table = 'every_time';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, $table);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n    }\n\n    public function testAsync(): void\n    {\n        $this->copyAsync();\n\n        $table1 = 'test';\n        $table2 = 'every_time';\n\n        $queue = config('deploy-operations.queue.name');\n\n        Queue::fake();\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        Queue::assertNothingPushed();\n\n        $this->assertDatabaseCount($table1, 0);\n        $this->assertDatabaseCount($table2, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'foo_bar');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'every_time');\n\n        $this->artisan(Names::Operations)->assertExitCode(0);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseOperationDoesntLike($this->table, 'foo_bar');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'every_time');\n\n        Queue::assertPushed(OperationJob::class, 2);\n\n        Queue::assertPushedOn($queue, OperationJob::class, fn (OperationJob $job) => Str::contains($job->filename, [\n            'foo_bar',\n            'every_time',\n        ]));\n    }\n\n    public function testSync(): void\n    {\n        $this->copyAsync();\n\n        $table1 = 'test';\n        $table2 = 'every_time';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table1, 0);\n        $this->assertDatabaseCount($table2, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'foo_bar');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'every_time');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table1, 1);\n        $this->assertDatabaseCount($table2, 1);\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, 'foo_bar');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'every_time');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table1, 1);\n        $this->assertDatabaseCount($table2, 2);\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, 'foo_bar');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'every_time');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table1, 1);\n        $this->assertDatabaseCount($table2, 3);\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, 'foo_bar');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'every_time');\n    }\n\n    public function testViaMigrationMethod(): void\n    {\n        $this->copyViaMigrations();\n\n        $table = 'test';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'custom');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'invoke');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'up_down');\n        $this->assertDatabaseOperationDoesntLike($table, 'custom', column: 'value');\n        $this->assertDatabaseOperationDoesntLike($table, 'invoke', column: 'value');\n        $this->assertDatabaseOperationDoesntLike($table, 'up_down', column: 'value');\n\n        $this->loadMigrationsFrom(__DIR__ . '/../fixtures/migrations_with_operations');\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 2);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'custom');\n        $this->assertDatabaseOperationHas($this->table, 'invoke');\n        $this->assertDatabaseOperationHas($this->table, 'up_down');\n        $this->assertDatabaseOperationDoesntLike($table, 'custom', column: 'value');\n        $this->assertDatabaseOperationHas($table, 'invoke', column: 'value');\n        $this->assertDatabaseOperationHas($table, 'up_down', column: 'value');\n\n        $this->artisan(RollbackCommand::class, [\n            '--path'     => __DIR__ . '/../fixtures/migrations_with_operations',\n            '--realpath' => true,\n        ])->assertSuccessful();\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'custom');\n        $this->assertDatabaseOperationHas($this->table, 'invoke');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'up_down');\n        $this->assertDatabaseOperationDoesntLike($table, 'custom', column: 'value');\n        $this->assertDatabaseOperationHas($table, 'invoke', column: 'value');\n        $this->assertDatabaseOperationDoesntLike($table, 'up_down', column: 'value');\n    }\n}\n"
  },
  {
    "path": "tests/Commands/RollbackTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Commands;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse Exception;\nuse Illuminate\\Support\\Str;\nuse Tests\\TestCase;\nuse Throwable;\n\nclass RollbackTest extends TestCase\n{\n    public function testRollbackCommand(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 0);\n\n        $this->artisan(Names::Make, ['name' => 'RollbackOne'])->assertExitCode(0);\n        $this->artisan(Names::Make, ['name' => 'RollbackTwo'])->assertExitCode(0);\n\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 2);\n\n        $this->assertDatabaseOperationHas($this->table, 'rollback_one');\n        $this->assertDatabaseOperationHas($this->table, 'rollback_two');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'rollback_tree');\n\n        $this->artisan(Names::Rollback)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 0);\n\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 2);\n\n        $this->artisan(Names::Make, ['name' => 'RollbackTree'])->assertExitCode(0);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 3);\n\n        $this->assertDatabaseOperationHas($this->table, 'rollback_one');\n        $this->assertDatabaseOperationHas($this->table, 'rollback_two');\n        $this->assertDatabaseOperationHas($this->table, 'rollback_tree');\n    }\n\n    public function testEnvironment(): void\n    {\n        $this->copyFiles();\n\n        $table = 'environment';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_all');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_testing');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_many_environments');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 5);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_on_all');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_production');\n        $this->assertDatabaseOperationHas($this->table, 'run_on_testing');\n        $this->assertDatabaseOperationHas($this->table, 'run_on_many_environments');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->artisan(Names::Rollback)->assertExitCode(0);\n        $this->assertDatabaseCount($table, 10);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_all');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_production');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_testing');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_on_many_environments');\n    }\n\n    public function testDownSuccess(): void\n    {\n        $this->copyFiles();\n\n        $table = 'success';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_success');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_success');\n\n        $this->artisan(Names::Rollback)->assertExitCode(0);\n        $this->assertDatabaseCount($table, 4);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_success');\n    }\n\n    public function testDownSuccessOnFailed(): void\n    {\n        $this->copyFiles();\n\n        $table = 'success';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_success_on_failed');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_success_on_failed');\n\n        try {\n            $this->copySuccessFailureMethod();\n\n            $this->table()->insert(['operation' => '2021_12_23_165048_run_success_on_failed', 'batch' => 999]);\n\n            $this->assertDatabaseCount($table, 2);\n            $this->assertDatabaseCount($this->table, 13);\n            $this->assertDatabaseOperationHas($this->table, 'run_success_on_failed');\n\n            $this->artisan(Names::Rollback)->assertExitCode(1);\n        } catch (Throwable $e) {\n            $this->assertInstanceOf(Exception::class, $e);\n\n            $this->assertSame('Custom exception', $e->getMessage());\n\n            $this->assertTrue(Str::contains($e->getFile(), 'run_success_on_failed'));\n        }\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 13);\n        $this->assertDatabaseOperationHas($this->table, 'run_success_on_failed');\n    }\n\n    public function testDownFailed(): void\n    {\n        $this->copyFiles();\n\n        $table = 'failed';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_failed');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'run_failed');\n\n        $this->artisan(Names::Rollback)->assertExitCode(0);\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_failed');\n    }\n\n    public function testUpFailedOnException(): void\n    {\n        $this->copyFiles();\n\n        $table = 'failed';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_failed_failure');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'run_failed_failure');\n\n        try {\n            $this->copyFailedMethod();\n\n            $this->table()->insert(['operation' => '2021_12_23_184029_run_failed_failure', 'batch' => 999]);\n\n            $this->artisan(Names::Rollback)->assertExitCode(0);\n        } catch (Throwable $e) {\n            $this->assertInstanceOf(Exception::class, $e);\n\n            $this->assertSame('Custom exception', $e->getMessage());\n\n            $this->assertTrue(Str::contains($e->getFile(), 'run_failed_failure'));\n        }\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 13);\n        $this->assertDatabaseOperationHas($this->table, 'run_failed_failure');\n    }\n\n    public function testDisabledBefore(): void\n    {\n        $this->copyFiles();\n\n        $table = 'before';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 12);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationHas($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->artisan(Names::Rollback)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 4);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n    }\n\n    public function testEnabledBefore(): void\n    {\n        $this->copyFiles();\n\n        $table = 'before';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations, ['--before' => true])->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 11);\n        $this->assertDatabaseOperationHas($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n        $this->artisan(Names::Operations, ['--before' => true])->assertExitCode(0);\n\n        $this->artisan(Names::Rollback)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 2);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_enabled');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'test_before_disabled');\n    }\n\n    public function testDI(): void\n    {\n        $this->copyDI();\n\n        $table = 'test';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'invoke');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'invoke_down');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'up_down');\n        $this->assertDatabaseOperationDoesntLike($table, 'up_down', column: 'value');\n        $this->assertDatabaseOperationDoesntLike($table, 'invoke_down', column: 'value');\n        $this->assertDatabaseOperationDoesntLike($table, 'invoke', column: 'value');\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 3);\n        $this->assertDatabaseCount($this->table, 3);\n        $this->assertDatabaseOperationHas($this->table, 'invoke');\n        $this->assertDatabaseOperationHas($this->table, 'invoke_down');\n        $this->assertDatabaseOperationHas($this->table, 'up_down');\n        $this->assertDatabaseOperationHas($table, 'up_down', column: 'value');\n        $this->assertDatabaseOperationHas($table, 'invoke_down', column: 'value');\n        $this->assertDatabaseOperationHas($table, 'invoke', column: 'value');\n\n        $this->artisan(Names::Rollback)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'invoke');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'invoke_down');\n        $this->assertDatabaseOperationDoesntLike($this->table, 'up_down');\n        $this->assertDatabaseOperationDoesntLike($table, 'up_down', column: 'value');\n        $this->assertDatabaseOperationDoesntLike($table, 'invoke_down', column: 'value');\n        $this->assertDatabaseOperationHas($table, 'invoke', column: 'value');\n    }\n}\n"
  },
  {
    "path": "tests/Commands/StatusTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Commands;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse Tests\\TestCase;\n\nclass StatusTest extends TestCase\n{\n    public function testNotFound(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Status)->assertExitCode(0);\n\n        $this->assertDatabaseDoesntTable($this->table);\n    }\n\n    public function testStatusCommand(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 0);\n\n        $this->artisan(Names::Status)->expectsTable([], [])->assertExitCode(0);\n\n        $this->artisan(Names::Make, ['name' => 'Status'])->assertExitCode(0);\n        $this->artisan(Names::Operations)->assertExitCode(0);\n\n        $this->assertDatabaseCount($this->table, 1);\n\n        $this->artisan(Names::Status)->assertExitCode(0);\n\n        $this->assertDatabaseOperationHas($this->table, 'status');\n    }\n}\n"
  },
  {
    "path": "tests/Concerns/AssertDatabase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Concerns;\n\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Schema;\n\n/** @mixin \\Tests\\TestCase */\ntrait AssertDatabase\n{\n    protected function assertDatabaseHasTable(string $table): void\n    {\n        $this->assertTrue(\n            $this->hasTable($table)\n        );\n    }\n\n    protected function assertDatabaseDoesntTable(string $table): void\n    {\n        $this->assertFalse(\n            $this->hasTable($table)\n        );\n    }\n\n    protected function assertDatabaseOperationHas(\n        string $table,\n        $value,\n        $connection = null,\n        string $column = 'operation'\n    ): void {\n        $this->assertDatabaseHasLike($table, $column, $value, $connection);\n    }\n\n    protected function assertDatabaseHasLike(string $table, string $column, $value, $connection = null): void\n    {\n        $exists = DB::connection($connection)\n            ->table($table)\n            ->whereRaw(\"$column like '%$value%'\")\n            ->exists();\n\n        $this->assertTrue($exists);\n    }\n\n    protected function assertDatabaseOperationDoesntLike(\n        string $table,\n        $value,\n        $connection = null,\n        string $column = 'operation'\n    ): void {\n        $this->assertDatabaseDoesntLike($table, $column, $value, $connection);\n    }\n\n    protected function assertDatabaseDoesntLike(string $table, string $column, $value, $connection = null): void\n    {\n        $exists = DB::connection($connection)\n            ->table($table)\n            ->whereRaw(\"$column like '%$value%'\")\n            ->doesntExist();\n\n        $this->assertTrue($exists);\n    }\n\n    protected function hasTable(string $table): bool\n    {\n        return Schema::hasTable($table);\n    }\n}\n"
  },
  {
    "path": "tests/Concerns/Database.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Concerns;\n\ntrait Database\n{\n    protected string $database = 'testing';\n\n    protected string $table = 'foo_operations';\n\n    protected function setDatabase($app): void\n    {\n        $app['config']->set('database.default', $this->database);\n\n        $app['config']->set('database.connections.' . $this->database, [\n            'driver'   => 'sqlite',\n            'database' => ':memory:',\n            'prefix'   => '',\n        ]);\n\n        $app['config']->set('deploy-operations.connection', $this->database);\n        $app['config']->set('deploy-operations.table', $this->table);\n    }\n\n    protected function freshDatabase(): void\n    {\n        $this->loadMigrationsFrom(__DIR__ . '/../fixtures/migrations');\n\n        $this->artisan('migrate')->run();\n    }\n}\n"
  },
  {
    "path": "tests/Concerns/Files.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Concerns;\n\nuse DragonCode\\Support\\Facades\\Filesystem\\Directory;\nuse Illuminate\\Support\\Facades\\File;\n\n/** @mixin \\Tests\\TestCase */\ntrait Files\n{\n    protected function freshFiles(): void\n    {\n        Directory::ensureDelete([\n            $this->targetDirectory(),\n            $this->stubsDirectory(),\n        ]);\n    }\n\n    protected function copyFiles(): void\n    {\n        File::copyDirectory(\n            __DIR__ . '/../fixtures/app/operations',\n            $this->targetDirectory()\n        );\n    }\n\n    protected function copyAsync(): void\n    {\n        File::copyDirectory(\n            __DIR__ . '/../fixtures/app/async',\n            $this->targetDirectory()\n        );\n    }\n\n    protected function copyEmptyDirectory(): void\n    {\n        File::copyDirectory(\n            __DIR__ . '/../fixtures/app/empty',\n            $this->targetDirectory()\n        );\n    }\n\n    protected function copyDI(): void\n    {\n        File::copyDirectory(\n            __DIR__ . '/../fixtures/app/di',\n            $this->targetDirectory()\n        );\n    }\n\n    protected function copyViaMigrations(): void\n    {\n        File::copyDirectory(\n            __DIR__ . '/../fixtures/app/via_migrations',\n            $this->targetDirectory()\n        );\n    }\n\n    protected function copySuccessFailureMethod(): void\n    {\n        File::copy(\n            __DIR__ . '/../fixtures/app/operations_failed/2021_12_23_165048_run_success_on_failed.php',\n            $this->targetDirectory('2021_12_23_165048_run_success_on_failed.php')\n        );\n    }\n\n    protected function copyFailedMethod(): void\n    {\n        File::copy(\n            __DIR__ . '/../fixtures/app/operations_failed/2021_12_23_184029_run_failed_failure.php',\n            $this->targetDirectory('2021_12_23_184029_run_failed_failure.php')\n        );\n    }\n\n    protected function copySuccessTransaction(): void\n    {\n        File::copy(\n            __DIR__ . '/../fixtures/app/stubs/2021_02_15_124237_test_success_transactions.stub',\n            $this->targetDirectory('2021_02_15_124237_test_success_transactions.php')\n        );\n    }\n\n    protected function copyFailedTransaction(): void\n    {\n        File::copy(\n            __DIR__ . '/../fixtures/app/stubs/2021_02_15_124852_test_failed_transactions.stub',\n            $this->targetDirectory('2021_02_15_124852_test_failed_transactions.php')\n        );\n    }\n\n    protected function targetDirectory(string $path = ''): string\n    {\n        $dir = $this->getOperationsPath();\n\n        File::ensureDirectoryExists($dir);\n\n        return rtrim($dir, '/\\\\') . '/' . ltrim($path, '/\\\\');\n    }\n\n    protected function stubsDirectory(): string\n    {\n        return base_path('stubs');\n    }\n\n    protected function getOperationsPath(): string\n    {\n        return $this->app['config']->get('deploy-operations.path');\n    }\n}\n"
  },
  {
    "path": "tests/Concerns/Some.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Concerns;\n\nclass Some\n{\n    public function get(string $value): string\n    {\n        return $value;\n    }\n}\n"
  },
  {
    "path": "tests/Helpers/GitTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Helpers;\n\nuse DragonCode\\LaravelDeployOperations\\Helpers\\GitHelper;\nuse Tests\\TestCase;\n\nclass GitTest extends TestCase\n{\n    public function testCurrentBranchNull(): void\n    {\n        $this->assertNull($this->git()->currentBranch(__DIR__));\n    }\n\n    public function testCurrentBranch(): void\n    {\n        $branch = $this->git()->currentBranch(__DIR__ . '/../../');\n\n        $this->assertIsString($branch);\n    }\n\n    protected function git(): GitHelper\n    {\n        return $this->app->make(GitHelper::class);\n    }\n}\n"
  },
  {
    "path": "tests/Helpers/OperationTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Helpers;\n\nuse DragonCode\\LaravelDeployOperations\\Constants\\Names;\nuse DragonCode\\LaravelDeployOperations\\Helpers\\OperationHelper;\nuse Tests\\TestCase;\n\nclass OperationTest extends TestCase\n{\n    public function testSuccess(): void\n    {\n        $this->assertDatabaseDoesntTable($this->table);\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseHasTable($this->table);\n        $this->assertDatabaseCount($this->table, 0);\n\n        $this->artisan(Names::Make, ['name' => 'TestMigration'])->assertExitCode(0);\n\n        OperationHelper::run();\n\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, 'test_migration');\n    }\n\n    public function testPath(): void\n    {\n        $this->copyFiles();\n\n        $table = 'test';\n\n        $path = 'sub_path/2021_12_15_205804_baz.php';\n\n        $this->artisan(Names::Install)->assertExitCode(0);\n\n        $this->assertDatabaseCount($table, 0);\n        $this->assertDatabaseCount($this->table, 0);\n        $this->assertDatabaseOperationDoesntLike($this->table, 'baz');\n\n        OperationHelper::run($path);\n\n        $this->assertDatabaseCount($table, 1);\n        $this->assertDatabaseCount($this->table, 1);\n        $this->assertDatabaseOperationHas($this->table, 'baz');\n\n        $this->assertSame('sub_path/2021_12_15_205804_baz', $this->table()->first()->operation);\n    }\n}\n"
  },
  {
    "path": "tests/Helpers/SorterTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Helpers;\n\nuse DragonCode\\LaravelDeployOperations\\Helpers\\SorterHelper;\nuse Tests\\TestCase;\n\nclass SorterTest extends TestCase\n{\n    public function testByValues(): void\n    {\n        $expected = [\n            '2022_10_13_013321_test1',\n            'foo/2022_10_13_013322_test2',\n            'bar/2022_10_13_013323_test3',\n            'foo/2022_10_13_013324_test4',\n            'bar/2022_10_13_013325_test5',\n            '2022_10_13_013326_test6',\n        ];\n\n        $values = [\n            '2022_10_13_013321_test1',\n            '2022_10_13_013326_test6',\n            'bar/2022_10_13_013323_test3',\n            'bar/2022_10_13_013325_test5',\n            'foo/2022_10_13_013322_test2',\n            'foo/2022_10_13_013324_test4',\n        ];\n\n        $this->assertSame($expected, $this->sorter()->byValues($values));\n    }\n\n    public function testByKeys(): void\n    {\n        $expected = [\n            '2022_10_13_013321_test1'     => 1,\n            'foo/2022_10_13_013322_test2' => 2,\n            'bar/2022_10_13_013323_test3' => 3,\n            'foo/2022_10_13_013324_test4' => 4,\n            'bar/2022_10_13_013325_test5' => 5,\n            '2022_10_13_013326_test6'     => 6,\n        ];\n\n        $values = [\n            '2022_10_13_013321_test1'     => 1,\n            '2022_10_13_013326_test6'     => 6,\n            'bar/2022_10_13_013323_test3' => 3,\n            'bar/2022_10_13_013325_test5' => 5,\n            'foo/2022_10_13_013322_test2' => 2,\n            'foo/2022_10_13_013324_test4' => 4,\n        ];\n\n        $this->assertSame($expected, $this->sorter()->byKeys($values));\n    }\n\n    public function testByRan(): void\n    {\n        $items = [\n            '2022_10_13_013321_test1',\n            'foo/2022_10_13_013322_test2',\n            'bar/2022_10_13_013323_test3',\n            'foo/2022_10_13_013324_test4',\n            'bar/2022_10_13_013325_test5',\n            '2022_10_13_013326_test6',\n        ];\n\n        $completed = [\n            '2022_10_13_013321_test1',\n            'foo/2022_10_13_013324_test4',\n            'bar/2022_10_13_013325_test5',\n        ];\n\n        $expected = [\n            '2022_10_13_013321_test1',\n            'foo/2022_10_13_013324_test4',\n            'bar/2022_10_13_013325_test5',\n            'foo/2022_10_13_013322_test2',\n            'bar/2022_10_13_013323_test3',\n            '2022_10_13_013326_test6',\n        ];\n\n        $this->assertSame($expected, $this->sorter()->byRan($items, $completed));\n    }\n\n    protected function sorter(): SorterHelper\n    {\n        return new SorterHelper;\n    }\n}\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests;\n\nuse DragonCode\\LaravelDeployOperations\\Repositories\\OperationsRepository;\nuse DragonCode\\LaravelDeployOperations\\ServiceProvider;\nuse Illuminate\\Container\\Container;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Foundation\\Testing\\RefreshDatabase;\nuse Illuminate\\Support\\Facades\\DB;\nuse Orchestra\\Testbench\\TestCase as BaseTestCase;\nuse Spatie\\LaravelData\\LaravelDataServiceProvider;\nuse Tests\\Concerns\\AssertDatabase;\nuse Tests\\Concerns\\Database;\nuse Tests\\Concerns\\Files;\n\nabstract class TestCase extends BaseTestCase\n{\n    use AssertDatabase;\n    use Database;\n    use Files;\n    use RefreshDatabase;\n\n    protected function setUp(): void\n    {\n        parent::setUp();\n\n        $this->freshDatabase();\n        $this->freshFiles();\n    }\n\n    protected function getPackageProviders($app): array\n    {\n        return [\n            ServiceProvider::class,\n            LaravelDataServiceProvider::class,\n        ];\n    }\n\n    protected function getEnvironmentSetUp($app): void\n    {\n        parent::getEnvironmentSetUp($app);\n\n        $this->setDatabase($app);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table($this->table);\n    }\n\n    protected function repository(): OperationsRepository\n    {\n        return Container::getInstance()->make(OperationsRepository::class);\n    }\n}\n"
  },
  {
    "path": "tests/fixtures/app/async/2021_04_06_212742_every_time.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function __invoke(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('every_time');\n    }\n\n    public function shouldOnce(): bool\n    {\n        return false;\n    }\n\n    public function needAsync(): bool\n    {\n        return true;\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/async/2023_04_06_212637_foo_bar.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function __invoke(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n\n    public function needAsync(): bool\n    {\n        return true;\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/di/2022_10_11_234251_invoke.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Tests\\Concerns\\Some;\n\nreturn new class extends Operation {\n    public function __invoke(Some $some): void\n    {\n        $this->table()->insert([\n            'value' => $some->get('invoke'),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/di/2022_10_11_234251_invoke_down.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Tests\\Concerns\\Some;\n\nreturn new class extends Operation {\n    public function __invoke(Some $some): void\n    {\n        $this->table()->insert([\n            'value' => $some->get('invoke_down'),\n        ]);\n    }\n\n    public function down(Some $some): void\n    {\n        $this->table()\n            ->where('value', $some->get('invoke_down'))\n            ->delete();\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/di/2022_10_11_234312_up_down.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Tests\\Concerns\\Some;\n\nreturn new class extends Operation {\n    public function up(Some $some): void\n    {\n        $this->table()->insert([\n            'value' => $some->get('up_down'),\n        ]);\n    }\n\n    public function down(Some $some): void\n    {\n        $this->table()\n            ->where('value', $some->get('up_down'))\n            ->delete();\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/empty/.gitkeep",
    "content": ""
  },
  {
    "path": "tests/fixtures/app/empty/some.txt",
    "content": ""
  },
  {
    "path": "tests/fixtures/app/operations/2020_12_07_153105_foo_bar.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->truncate();\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_01_02_020947_every_time.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('every_time');\n    }\n\n    public function shouldOnce(): bool\n    {\n        return false;\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_05_24_120003_run_on_all.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('environment');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_05_24_120003_run_on_many_environments.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('environment');\n    }\n\n    public function shouldRun(): bool\n    {\n        return in_array(app()->environment(), ['testing', 'production'], true);\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_05_24_120003_run_on_production.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('environment');\n    }\n\n    public function shouldRun(): bool\n    {\n        return app()->environment() === 'production';\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_05_24_120003_run_on_testing.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('environment');\n    }\n\n    public function shouldRun(): bool\n    {\n        return app()->environment() === 'testing';\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_06_07_132849_run_except_production.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('environment');\n    }\n\n    public function shouldRun(): bool\n    {\n        return app()->environment() !== 'production';\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_06_07_132917_run_except_testing.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('environment');\n    }\n\n    public function shouldRun(): bool\n    {\n        return app()->environment() !== 'testing';\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_06_07_134045_run_except_many_environments.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('environment');\n    }\n\n    public function shouldRun(): bool\n    {\n        return app()->environment() === 'testing'\n            && ! in_array(app()->environment(), ['testing', 'production'], true);\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_10_26_143247_run_allow.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('environment');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_10_26_143304_run_disallow.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('environment');\n    }\n\n    public function shouldRun(): bool\n    {\n        return false;\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_12_23_165047_run_success.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function success(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('success');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2021_12_23_184029_run_failed.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void {}\n\n    public function down(): void {}\n\n    public function failed(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('success');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2022_08_17_135147_test_before_enabled.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('before');\n    }\n\n    public function needBefore(): bool\n    {\n        return true;\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/2022_08_17_135153_test_before_disabled.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('before');\n    }\n\n    public function needBefore(): bool\n    {\n        return false;\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/sub_path/2021_12_15_205804_baz.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->truncate();\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations/sub_path/2022_10_27_230732_foo.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    public function down(): void\n    {\n        $this->table()->truncate();\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations_failed/2021_12_23_165048_run_success_on_failed.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        throw new Exception('Custom exception');\n    }\n\n    public function down(): void\n    {\n        throw new Exception('Custom exception');\n    }\n\n    public function success(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('success');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/operations_failed/2021_12_23_184029_run_failed_failure.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        throw new Exception('Custom exception');\n    }\n\n    public function down(): void\n    {\n        throw new Exception('Custom exception');\n    }\n\n    public function failed(): void\n    {\n        $this->table()->insert([\n            'value' => Str::random(4),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('failed');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/stubs/2021_02_15_124237_test_success_transactions.stub",
    "content": "<?php\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            $this->value(),\n            $this->value(),\n            $this->value(),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('transactions');\n    }\n\n    protected function value(): array\n    {\n        return ['value' => Str::random(4)];\n    }\n\n    public function withinTransactions(): bool\n    {\n        return true;\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/stubs/2021_02_15_124852_test_failed_transactions.stub",
    "content": "<?php\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Str;\n\nreturn new class extends Operation {\n    public function up(): void\n    {\n        $this->table()->insert([\n            $this->value(),\n            $this->value(),\n            $this->value(),\n        ]);\n\n        throw new Exception('Random message');\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('transactions');\n    }\n\n    protected function value(): array\n    {\n        return ['value' => Str::random(4)];\n    }\n\n    public function withinTransactions(): bool\n    {\n        return true;\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/stubs/customized.stub",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Foo\\Bar\\Some;\n\nreturn new class extends Some {\n    public function __invoke(): void\n    {\n        // some code\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/stubs/make_example.stub",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\n\nreturn new class extends Operation {\n    public function __invoke(): void\n    {\n        //\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/via_migrations/2025_03_31_213407_custom.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Tests\\Concerns\\Some;\n\nreturn new class extends Operation {\n    public function __invoke(Some $some): void\n    {\n        $this->table()->insert([\n            'value' => $some->get('custom'),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/via_migrations/2025_03_31_234251_invoke.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Tests\\Concerns\\Some;\n\nreturn new class extends Operation {\n    public function __invoke(Some $some): void\n    {\n        $this->table()->insert([\n            'value' => $some->get('invoke'),\n        ]);\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/app/via_migrations/2025_03_31_234312_up_down.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse DragonCode\\LaravelDeployOperations\\Operation;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Facades\\DB;\nuse Tests\\Concerns\\Some;\n\nreturn new class extends Operation {\n    public function up(Some $some): void\n    {\n        $this->table()->insert([\n            'value' => $some->get('up_down'),\n        ]);\n    }\n\n    public function down(Some $some): void\n    {\n        $this->table()\n            ->where('value', $some->get('up_down'))\n            ->delete();\n    }\n\n    protected function table(): Builder\n    {\n        return DB::table('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/migrations/2020_12_07_164624_create_test_table.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        Schema::create('test', function (Blueprint $table) {\n            $table->uuid('value')->unique();\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('test');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/migrations/2021_01_02_022431_create_every_time_table.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        Schema::create('every_time', function (Blueprint $table) {\n            $table->uuid('value');\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('every_time');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/migrations/2021_02_15_124419_create_transactions_table.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        Schema::create('transactions', function (Blueprint $table) {\n            $table->uuid('value');\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('transactions');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/migrations/2021_05_24_122027_create_environment_table.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        Schema::create('environment', function (Blueprint $table) {\n            $table->uuid('value');\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('environment');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/migrations/2021_12_23_165218_create_success_table.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        Schema::create('success', function (Blueprint $table) {\n            $table->string('value');\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('success');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/migrations/2021_12_23_184434_create_failed_table.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        Schema::create('failed', function (Blueprint $table) {\n            $table->string('value');\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('failed');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/migrations/2022_08_17_150549_create_before_table.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration {\n    public function up(): void\n    {\n        Schema::create('before', function (Blueprint $table) {\n            $table->string('value');\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('before');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/migrations_with_operations/2025_03_31_213847_call_invokable.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\n\nuse function DragonCode\\LaravelDeployOperations\\operation;\n\nreturn new class extends Migration {\n    public function up(): void {}\n\n    public function withOperation(): string\n    {\n        return operation('2025_03_31_234251_invoke');\n    }\n};\n"
  },
  {
    "path": "tests/fixtures/migrations_with_operations/2025_03_31_213921_call_up_down.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Illuminate\\Database\\Migrations\\Migration;\n\nuse function DragonCode\\LaravelDeployOperations\\operation;\n\nreturn new class extends Migration {\n    public function up(): void {}\n\n    public function down(): void {}\n\n    public function withOperation(): string\n    {\n        return operation('2025_03_31_234312_up_down');\n    }\n};\n"
  }
]