diff --git a/.editorconfig b/.editorconfig index c4c9a485..d52268e3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,16 +2,415 @@ root = true indent_style = space indent_size = 4 +tab_width = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true +max_line_length = 140 +rulers = 80,100,120 + +[.editorconfig] +max_line_length = 165 # Can't multiline the string so have to do this. + +[flake.{nix,lock}] +indent_size = 2 + +[*.md] +indent_size = 2 +max_line_length = 180 + +[.github/workflows/*.{yaml,yml}] +max_line_length = 180 + +# Actually go fuck yourself microsoft. +[*.{ps1,psm1}] +charset = utf-8-bom + +[*.{patch,diff}] +trim_trailing_whitespace = false +insert_final_newline = false [*.{cmd,bat,cmd,vbs,bas}] end_of_line = crlf -[*.{yml,yaml}] +[*.{yml,yaml,json,jsonc}] indent_size = 2 [*.{xml,xsd,wsb,csproj}] indent_size = 2 + +#region C# +[*.sln] +indent_style = tab + +[*.{csproj,vbproj,vcxproj.filters,proj,projiFems,shproj,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}] +indent_size = 2 + +[packages.lock.json] +end_of_line = crlf +insert_final_newline = false + +########################################## +# Default .NET Code Style Severities +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope +########################################## +[*.{cs,csx,cake,vb,vbx}] +# Default Severity for all .NET Code Style rules below +dotnet_analyzer_diagnostic.severity = warning + +########################################## +# Language Rules - .NET +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules +########################################## +[*.{cs,csx,cake,vb,vbx}] + +# Expression-level preferences +dotnet_style_object_initializer = true +dotnet_style_collection_initializer = true +dotnet_style_coalesce_expression = true +dotnet_style_null_propagation = true +dotnet_style_prefer_auto_properties = true +dotnet_style_explicit_tuple_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = false +dotnet_diagnotic.IDE0046.severity = suggestion +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_simplified_interpolation = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_namespace_match_folder = true +dotnet_diagnostic.IDE0130.severity = suggestion +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed + +# Field Preferences +dotnet_style_readonly_field = true +dotnet_diagnostic.CA1051.severity = none + +# Language keyword vs. framework types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = always + +# Parameter preferences +dotnet_code_quality_unused_parameters = all + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# "this."" preferences +dotnet_style_qualification_for_field = true +dotnet_style_qualification_for_property = true +dotnet_style_qualification_for_method = true +dotnet_style_qualification_for_event = true + +########################################## +# Language Rules - C# +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules +########################################## +[*.{cs,csx,cake}] +# File header preferences +file_header_template = Copyright (c) James Draycott. All Rights Reserved.\nLicensed under the GPL3 License, See LICENSE in the project root for license information. + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace + +# Code-block preferences +csharp_prefer_braces = false +csharp_prefer_simple_using_statement = true +dotnet_diagnostic.IDE0063.severity = suggestion +csharp_style_namespace_declarations = file_scoped +csharp_style_prefer_method_group_conversion = true +csharp_style_prefer_top_level_statements = true + +# Expression-bodied members +csharp_style_expression_bodied_constructors = true +csharp_style_expression_bodied_methods = true +csharp_style_expression_bodied_operators = true +csharp_style_expression_bodied_properties = true +csharp_style_expression_bodied_indexers = true +csharp_style_expression_bodied_accessors = true +csharp_style_expression_bodied_lambdas = true +csharp_style_expression_bodied_local_functions = true + +# Expression-level preferences +csharp_style_unused_value_expression_statement_preference = discard_variable +dotnet_diagnostic.IDE0058.severity = none +csharp_style_unused_value_assignment_preference = discard_variable +dotnet_diagnostic.IDE0059.severity = suggestion +csharp_style_throw_expression = true +csharp_style_inlined_variable_declaration = true +csharp_prefer_simple_default_expression = true +csharp_style_pattern_local_over_anonymous_function = true +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_range_operator = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_tuple_swap = true +csharp_style_prefer_utf8_string_literals = true + +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +csharp_prefer_static_local_function = true +csharp_style_prefer_readonly_struct = true +csharp_style_prefer_readonly_struct_member = true + +# "null" checking preferences +csharp_style_conditional_delegate_call = true + +# Pattern-matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_switch_expression = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_extended_property_pattern = true + +# 'var' preferences +csharp_style_var_for_built_in_types = true +csharp_style_var_when_type_is_apparent = true +csharp_style_var_elsewhere = true + +# Undocumented +# https://github.com/dotnet/docs/issues/28791 +csharp_style_prefer_primary_constructors = true + +########################################## +# .NET Coding Conventions - .NET +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/dotnet-formatting-options +########################################## +[*.{cs,csx,cake,vb,vbx}] +# .NET code refactoring options +# https://learn.microsoft.com/visualstudio/ide/reference/code-styles-refactoring-options +dotnet_style_operator_placement_when_wrapping = beginning_of_line + +########################################## +# Formatting Rules - .NET +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/dotnet-formatting-options +########################################## +[*.{cs,csx,cake,vb,vbx}] +# Using directive options +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false + +########################################## +# Formatting Rules - C# +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/csharp-formatting-options +########################################## +[*.{cs,csx,cake}] +# Newline options +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#new-line-options +csharp_new_line_before_open_brace = none +csharp_new_line_before_else = false +csharp_new_line_before_catch = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation options +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#indentation-options +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = no_change +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents_when_block = false + + +# Spacing options +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#spacing-options +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_after_comma = true +csharp_space_before_comma = false +csharp_space_after_dot = false +csharp_space_before_dot = false +csharp_space_after_semicolon_in_for_statement = true +csharp_space_before_semicolon_in_for_statement = false +csharp_space_around_declaration_statements = false +csharp_space_before_open_square_brackets = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_square_brackets = false + +# Wrap options +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#wrap-options +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true + +########################################## +# .NET Naming Rules +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/naming-rules +########################################## +[*.{cs,csx,cake,vb,vbx}] + +########################################## +# Styles +########################################## + +# camel_case_style - Define the camelCase style +dotnet_naming_style.camel_case_style.capitalization = camel_case +# pascal_case_style - Define the PascalCase style +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# first_upper_style - The first character must start with an upper-case character +dotnet_naming_style.first_upper_style.capitalization = first_word_upper +# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I' +dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case +dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I +dotnet_naming_style.disallowed_style.capitalization = pascal_case +dotnet_naming_style.internal_error_style.capitalization = pascal_case + +########################################## +# .NET Design Guideline Field Naming Rules +# Naming rules for fields follow the .NET Framework design guidelines +# https://learn.microsoft.com/dotnet/standard/design-guidelines/ +########################################## + +# All public/protected/protected_internal constant fields must be PascalCase +# https://learn.microsoft.com/dotnet/standard/design-guidelines/field +dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected_internal, protected +dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const +dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field +dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group +dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = pascal_case_style +dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning + +# All public/protected/protected_internal static readonly fields must be PascalCase +# https://learn.microsoft.com/dotnet/standard/design-guidelines/field +dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected_internal, protected +dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly +dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field +dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group +dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style +dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning + +# No other public/protected/protected_internal fields are allowed +# https://learn.microsoft.com/dotnet/standard/design-guidelines/field +dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected_internal, protected +dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field +dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group +dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style +dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error + +########################################## +# StyleCop Field Naming Rules +# Naming rules for fields follow the StyleCop analyzers +# This does not override any rules using disallowed_style above +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers +########################################## + +# All constant fields must be PascalCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md +dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private +dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const +dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field +dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group +dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = pascal_case_style +dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.severity = warning + +# All static readonly fields must be PascalCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md +dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private +dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly +dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field +dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group +dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style +dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.severity = warning + +# No non-private instance fields are allowed +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md +dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected +dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field +dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group +dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style +dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error + +# Private fields must be PascalCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md +dotnet_naming_symbols.stylecop_private_fields_group.applicable_accessibilities = private +dotnet_naming_symbols.stylecop_private_fields_group.applicable_kinds = field +dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.symbols = stylecop_private_fields_group +dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.style = pascal_case_style +dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.severity = warning + +# Local variables must be camelCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md +dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local +dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local +dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group +dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style +dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.severity = silent + +# This rule should never fire. However, it's included for at least two purposes: +# First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers. +# Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#). +dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = * +dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field +dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group +dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style +dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error + + +########################################## +# Other Naming Rules +########################################## + +# All of the following must be PascalCase: +# - Namespaces +# https://learn.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md +# - Classes and Enumerations +# https://learn.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md +# - Delegates +# https://learn.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types +# - Constructors, Properties, Events, Methods +# https://learn.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members +dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property +dotnet_naming_rule.element_rule.symbols = element_group +dotnet_naming_rule.element_rule.style = pascal_case_style +dotnet_naming_rule.element_rule.severity = warning + +# Interfaces use PascalCase and are prefixed with uppercase 'I' +# https://learn.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces +dotnet_naming_symbols.interface_group.applicable_kinds = interface +dotnet_naming_rule.interface_rule.symbols = interface_group +dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style +dotnet_naming_rule.interface_rule.severity = warning + +# Generics Type Parameters use PascalCase +# https://learn.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces +dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter +dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group +dotnet_naming_rule.type_parameter_rule.style = pascal_case_style +dotnet_naming_rule.type_parameter_rule.severity = warning + +# Function parameters use camelCase +# https://learn.microsoft.com/dotnet/standard/design-guidelines/naming-parameters +dotnet_naming_symbols.parameters_group.applicable_kinds = parameter +dotnet_naming_rule.parameters_rule.symbols = parameters_group +dotnet_naming_rule.parameters_rule.style = camel_case_style +dotnet_naming_rule.parameters_rule.severity = warning +#endregion diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..095d9077 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake . --no-pure-eval --accept-flake-config diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..c77e28bb --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +* text=auto eol=lf + +*.cmd text eol=crlf +*.bat text eol=crlf +*.vbs text eol=crlf +*.bas text eol=crlf diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 00000000..b7747ce8 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,35 @@ +name: Build Compiler + +on: + push: + branches: [ master ] + paths: ["src/Compiler/**", ".github/workflows/build.yaml"] + pull_request: + paths: ["src/Compiler/**", ".github/workflows/build.yaml"] + workflow_call: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + + - name: Setup DotNet + uses: actions/setup-dotnet@v4 + with: + cache: true + dotnet-version: 10.0.x + cache-dependency-path: "src/Compiler/packages.lock.json" + + - name: Install dependencies + run: dotnet restore + + - name: Build + run: dotnet publish ./src/Compiler/Compiler.csproj -c Release -r win-x64 + + - uses: actions/upload-artifact@v4 + with: + name: Compiler + path: ./src/Compiler/bin/Release/win-x64/publish/Compiler.exe diff --git a/.github/workflows/compile-scripts.yaml b/.github/workflows/compile-scripts.yaml new file mode 100644 index 00000000..b23e621a --- /dev/null +++ b/.github/workflows/compile-scripts.yaml @@ -0,0 +1,87 @@ +name: Powershell Compiler + +on: + push: + branches: [master] + paths: [ "src/**/*.ps1", ".github/workflows/compile-scripts.yaml" ] + pull_request: + paths: [ "src/**/*.ps1", ".github/workflows/compile-scripts.yaml" ] + workflow_dispatch: + +jobs: + changes: + runs-on: ubuntu-latest + outputs: + compiled: ${{ steps.changes.outputs.compiled }} + src: ${{ steps.changes.outputs.src }} + src_deleted: ${{ steps.changes.outputs.src_deleted }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + # Checks for changes in the 'compiled' and 'src' directories + # We also check for deleted files so we can cleanup the compiled directory + - name: Collect Changes for Upcoming Jobs + uses: dorny/paths-filter@v3.0.2 + id: changes + with: + list-files: shell + filters: | + compiled: + - 'compiled/**' + src: + - 'src/**/*.(ps1|psm1)' + src_deleted: + - deleted: 'src/**/*.(ps1|psm1)' + + cleanup-directory: + runs-on: ubuntu-latest + needs: changes + if: needs.changes.outputs.src_deleted == 'true' + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Delete Compiled versions of deleted files + id: delete_files + run: ./utils/clean-compiled.sh + + - name: Commit Changes + if: ${{ steps.delete_files.outputs.FOUND_DELETED == 'true' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore(compiled): Remove compiled versions of deleted files" + + build: + uses: ./.github/workflows/build.yaml + + compile-scripts: + runs-on: windows-latest + needs: [changes, build] + if: ${{ needs.changes.outputs.src == 'true' }} + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download Compiler Artifact + uses: dawidd6/action-download-artifact@v6 + with: + workflow: build.yaml + workflow_conclusion: success + name: Compiler + path: /tmp/Compiler + + - name: Run Compiler + shell: pwsh + run: /tmp/Compiler/Compiler.exe --input src --output compiled --force -vvv -f + + - name: Commit Changes + if: ${{ github.event_name == 'workflow_dispatch' || (needs.changes.outputs.src == 'true' && github.event_name == 'push') }} + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore(compiled): Compile scripts" diff --git a/.github/workflows/compiler.yaml b/.github/workflows/compiler.yaml deleted file mode 100644 index 9e361ae6..00000000 --- a/.github/workflows/compiler.yaml +++ /dev/null @@ -1,104 +0,0 @@ -name: Compiler - -on: - push: - branches: [master] - paths: - - "src/**" - - "compiled/**" - - "utils/Compiler.ps1" - - ".github/workflows/compiler.yaml" - pull_request: - paths: ["src/**", "compiled/**", "utils/Compiler.ps1"] - -jobs: - changes: - runs-on: ubuntu-latest - outputs: - compiled: ${{ steps.changes.outputs.compiled }} - src: ${{ steps.changes.outputs.src }} - src_deleted: ${{ steps.changes.outputs.src_deleted }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - # Checks for changes in the 'compiled' and 'src' directories - # We include 'utils/Compiler.ps1' in the 'src' directory incase it is modified - # As this can affect all scripts in the src directory. - # We also check for deleted files so we can cleanup the compiled directory - - name: Collect Changes for Upcoming Jobs - uses: dorny/paths-filter@v3.0.2 - id: changes - with: - list-files: shell - filters: | - compiled: - - 'compiled/**' - src: - - 'src/**' - - 'utils/Compiler.ps1' - src_deleted: - - deleted: 'src/**' - - protect-directory: - runs-on: ubuntu-latest - needs: changes - # Only run if changes have been made to the 'compiled' directory - if: ${{ needs.changes.outputs.compiled == 'true' && github.actor != 'github-actions' }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - # Don't run if the push was forced, as this is likely a cleanup. - - if: ${{ github.event_name != 'push' && !github.event.forced }} - run: | - echo "Manual changes to 'compiled' directory are not allowed." - exit 1 - - cleanup-directory: - runs-on: ubuntu-latest - needs: changes - if: needs.changes.outputs.src_deleted == 'true' - permissions: - contents: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Delete Compiled versions of deleted files - id: delete_files - run: | - for file in $(find compiled -type f); do - no_prefix=${file#compiled/} - if [ ! -f "src/${no_prefix}" ]; then - echo ::set-output name=found_deleted::true - echo "Found deleted src file ${no_prefix}, deleting compiled version." - rm $file - fi - done - - - name: Commit Changes - if: ${{ steps.delete_files.outputs.found_deleted == 'true' && github.event_name == 'push' }} - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "chore(compiled): Remove compiled versions of deleted files" - - compile-scripts: - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.src == 'true' }} - permissions: - contents: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Compile Scripts - shell: pwsh - run: ./utils/Invoke-CompileAllScripts.ps1 -Debug -Verbose - - - name: Commit Changes - if: ${{ needs.changes.outputs.src == 'true' && github.event_name == 'push' }} - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "chore(compiled): Compile scripts" diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 853bac57..6d0f3fa7 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -1,18 +1,20 @@ -name: Documentaion +name: Generate PowerShell Docs on: push: - branches: [ master ] - paths: [ 'docs/**', 'src/**', 'utils/Generate-Documentation.ps1', '.github/workflows/documentation.yaml' ] - pull_request: - paths: [ 'docs/**', 'src/**' ] + branches: [master] + paths: + - "docs/**" + - "src/**" + - "utils/Generate-Documentation.ps1" + - ".github/workflows/documentation.yaml" jobs: update_docs: name: Update Documentation runs-on: ubuntu-latest outputs: - changes: ${{ steps.changes.outputs.changes }} + docs: ${{ steps.changes.outputs.docs }} permissions: contents: write pull-requests: write @@ -23,7 +25,9 @@ jobs: - name: Generate Documentation shell: pwsh - run: .\utils\Generate-Documentation.ps1 + run: | + Install-Module -Name platyPS -Scope CurrentUser + .\utils\Generate-Documentation.ps1 - name: Check for changes id: changes @@ -34,7 +38,7 @@ jobs: - 'docs/docs/**' - name: Commit changes - if: ${{ steps.changes.outputs.changes == 'true' }} + if: ${{ steps.changes.outputs.docs == 'true' }} uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: "chore(docs): Update documentation" @@ -43,7 +47,7 @@ jobs: name: Deploy Documentation runs-on: ubuntu-latest needs: update_docs - if : ${{ github.event_name == 'push' && needs.update_docs.outputs.changes.docs == 'true' }} + if: ${{ github.event_name == 'push' && needs.update_docs.outputs.docs == 'true' }} permissions: contents: read pull-requests: read diff --git a/.github/workflows/external.yaml b/.github/workflows/external.yaml new file mode 100644 index 00000000..3033bedd --- /dev/null +++ b/.github/workflows/external.yaml @@ -0,0 +1,30 @@ +name: External Script Updater + +on: + workflow_dispatch: + push: + paths: [ 'src/external/source/**', 'src/external/Update.ps1' ] + schedule: + - cron: '0 0 * * *' + +jobs: + update: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - name: Run Update Script + shell: pwsh + run: ./src/external/Update.ps1 + + - name: Validate Scripts + shell: pwsh + run: ./src/external/Update.ps1 -Validate + + - name: Commit Changes + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore(external): Update external scripts" + file_pattern: "src/external/scripts/*" diff --git a/.github/workflows/generate.yaml b/.github/workflows/generate.yaml new file mode 100644 index 00000000..95bc21f1 --- /dev/null +++ b/.github/workflows/generate.yaml @@ -0,0 +1,64 @@ +name: Generate Scripts + +on: + push: + branches: [master] + paths: + - "src/automation/registry/Generate.ps1" + - "src/automation/registry/definitions/**" + - ".github/workflows/generate.yaml" + +jobs: + generate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Collect Changes + uses: dorny/paths-filter@v3.0.2 + id: changes + with: + list-files: shell + filters: | + definition: + - 'src/automation/registry/definitions/**' + definition_deleted: + - deleted: 'src/automation/registry/definitions/**' + + - name: Remove Deleted Definitions + id: delete_files + if: ${{ steps.changes.outputs.definition_deleted == 'true' }} + run: | + shopt -s globstar nullglob + for file in src/automation/registry/definitions/**; do + no_prefix=${file#src/automation/registry/definitions/} + if [ ! -f "src/automation/registry/Generate.ps1" ]; then + echo "Found deleted definition file ${no_prefix}, deleting." + rm "$file" + fi + done + + DIR="src/automation/registry" + DEFINITIONS_DIR="${DIR}/definitions" + GENERATED_DIR="${DIR}/generated" + for file in "${GENERATED_DIR}"/*; do + no_prefix=${file#"$GENERATED_DIR"/} + without_extension=${no_prefix%.*} + fullWithoutExtension="${DEFINITIONS_DIR}/${without_extension}" + if [ ! -f "$fullWithoutExtension.json" ] && [ ! -f "$fullWithoutExtension.jsonc" ]; then + echo "FOUND_DELETED=true" >> "$GITHUB_OUTPUT" + echo "Found deleted generated file ${no_prefix}, deleting." + rm "$file" + fi + done + echo "Cleanup completed." + + - name: Execute Generate Script + if: ${{ steps.changes.outputs.definition == 'true' }} + run: pwsh src/automation/registry/Generate.ps1 + + - name: Commit Changes + if: ${{ (steps.changes.outputs.definition == 'true' || steps.delete_files.outputs.FOUND_DELETED == 'true') && github.event_name == 'push' }} + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore(Generated): Update generated scripts" diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index c9cf513d..7133f185 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -1,25 +1,37 @@ name: Lint -on: [workflow_dispatch] +on: + pull_request: + paths: ["src/**", "tests/**", "utils/**", ".github/workflows/**"] + push: + branches: [master] + paths: ["src/**", "tests/**", "utils/**", ".github/workflows/**"] jobs: - lint: - name: Lint + powershell: + name: PowerShell Lint runs-on: ubuntu-latest permissions: contents: read - packages: read - statuses: write + security-events: write + actions: read steps: - - name: Checkout repository + - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Super-Linter - uses: super-linter/super-linter@v6.7.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - EDITORCONFIG_FILE_NAME: ".editorconfig" - POWERSHELL_CONFIG_FILE: "PSScriptAnalyzerSettings.psd1" - FILTER_REGEX_EXCLUDE: ".*compiled/.*|.*docs/.*|LICENSE" + - name: Run PSScriptAnalyzer + uses: microsoft/psscriptanalyzer-action@main + with: + path: .\ + recurse: true + ignorePattern: '"n-sight/cleaners", "compiled/", "external/scripts"' + settings: .\PSScriptAnalyzerSettings.psd1 + output: results.sarif + + - name: Upload SARIF results + uses: github/codeql-action/upload-sarif@v3 + if: ${{ always() }} + with: + sarif_file: results.sarif diff --git a/.github/workflows/scan-secrets.yaml b/.github/workflows/scan-secrets.yaml index 613c964e..7e24d923 100644 --- a/.github/workflows/scan-secrets.yaml +++ b/.github/workflows/scan-secrets.yaml @@ -1,6 +1,9 @@ name: Scan for Secrets -on: [pull_request, push] +on: + push: + branches: [ master ] + pull_request: jobs: secrets-scan: diff --git a/.github/workflows/test-scripts.yaml b/.github/workflows/test-scripts.yaml deleted file mode 100644 index db82532a..00000000 --- a/.github/workflows/test-scripts.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: PowerShell Script Tests - -on: - push: - branches: [master] - paths: ["src/**", "tests/**", ".github/workflows/test-scripts.yaml"] - -jobs: - test: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Checkout Repo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Run Pester Tests - shell: pwsh - run: .\utils\Invoke-CodeCoverage.ps1 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 00000000..81650c79 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,101 @@ +name: Run Tests + +on: + push: + branches: [master] + paths: ["src/**", "tests/**", ".github/workflows/test.yaml"] + pull_request: + paths: ["src/**", "tests/**", ".github/workflows/test.yaml"] + +jobs: + what-changed: + runs-on: ubuntu-latest + outputs: + compiler: ${{ steps.changes.outputs.compiler }} + scripts: ${{ steps.changes.outputs.scripts }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Collect Changes for Upcoming Jobs + uses: dorny/paths-filter@v3.0.2 + id: changes + with: + list-files: shell + filters: | + compiler: + - 'src/Compiler/**' + - 'tests/Compiler/**' + scripts: + - 'src/**/*.(ps1|psm1)' + - 'tests/**/*.(ps1|psm1)' + + test-compiler: + name: Run Compiler Tests + runs-on: windows-latest + permissions: + contents: read + if: ${{ needs.what-changed.outputs.compiler == 'true' }} + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Setup DotNet + uses: actions/setup-dotnet@v4 + with: + cache: true + dotnet-version: 10.0.x + cache-dependency-path: "src/Compiler/packages.lock.json" + + - name: Install dependencies + run: dotnet restore + + - name: Test & Collect lcov coverage + run: dotnet test --logger trx /p:CollectCoverage=true /p:CoverletOutput=Coverage/ /p:CoverletOutputFormat=lcov + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + if: ${{ always() }} + with: + name: dotnet-coverage + path: ./tests/Compiler/Coverage/coverage.info + + test-scripts: + permissions: + contents: read + checks: write + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + name: Run Pester Tests on ${{ matrix.os }} + if : ${{ needs.what-changed.outputs.scripts == 'true' }} + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Install Dependencies + shell: pwsh + run: Install-Module -Name Pester -Scope CurrentUser -Force + + - name: Run Pester Tests + shell: pwsh + run: | + $Config = Import-PowerShellDataFile -Path "tests/PesterConfiguration.psd1"; + Invoke-Pester -Configuration $Config + + - name: Upload test results + if: always() + id: test-results + uses: natescherer/pester-tests-report@combined + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + gist_token: ${{ secrets.PESTER_GIST_GH_TOKEN }} + test_results_path: "tests/TestResults/PesterTestResults.xml" + coverage_paths: "tests/Coverage/PesterCodeCoverage.xml" + tests_fail_step: true + skip_check_run: true + coverage_gist: true + gist_name: "Pester Test Results on ${{ matrix.os }}" + report_name: "TEST_RESULTS_${{ github.run_id }}_${{ github.run_number }}_${{ matrix.os }}" diff --git a/.gitignore b/.gitignore index bbbef3f1..c68bfcf8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ .direnv -obj -bin +.devenv +result +.pre-commit-config.yaml +**/obj +**/bin +**/Output +**/coverage_report +**/TestResults +**/coverage.info +**/Coverage diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b2b47d30..78ec1674 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,11 +1,15 @@ { "recommendations": [ - "pspester.pester-test", - "markis.code-coverage", "editorconfig.editorconfig", + "formulahendry.code-runner", + "ironmansoftware.powershellprotools", + "markis.code-coverage", + "ms-dotnettools.csdevkit", + "ms-dotnettools.csharp", + "ms-vscode.powershell", + "pspester.pester-test", "ruschaaf.extended-embedded-languages", "tylerleonhardt.vscode-inline-values-powershell", - "ironmansoftware.powershellprotools", - "ms-vscode.powershell" + "vadimcn.vscode-lldb", ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index 78493811..101a92d2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,9 +18,12 @@ "request": "launch", "script": "${file}", "cwd": "${cwd}", - "args": [ "-Verbose", "-Debug" ], + "args": [ + "-Verbose", + "-Debug" + ], "createTemporaryIntegratedConsole": true, - "attachDotnetDebugger": true, + "attachDotnetDebugger": true }, { "name": "PowerShell: Launch Current File", @@ -29,6 +32,66 @@ "script": "${file}", "cwd": "${workspaceFolder}", "createTemporaryIntegratedConsole": true + }, + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/src/Compiler/bin/Debug/Compiler.exe", + "args": [ + "-i", + "${input:sourceDirectory}", + "-vvv", + "-o", + "${input:outputDirectory}", + "-f" + ], + "cwd": "${workspaceFolder}", + "console": "internalConsole", + "stopAtEntry": false, + "requireExactSource": true, + "internalConsoleOptions": "openOnSessionStart", + "justMyCode": true, + "enableStepFiltering": true + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}", + "justMyCode": false, + "requireExactSource": false + }, + { + "name": ".NET CLR Attach", + "type": "clr", + "request": "attach", + "processId": "${command:pickProcess}", + "justMyCode": false, + "requireExactSource": false + }, + { + "name": "Launch Windows Powershell with Debugger", + "type": "clr", + "request": "launch", + "justMyCode": false, + "requireExactSource": false, + "program": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", + } + ], + "inputs": [ + { + "id": "sourceDirectory", + "description": "The source directory containing the scripts to compile.", + "default": "src", + "type": "promptString" + }, + { + "id": "outputDirectory", + "description": "The output directory for the compiled scripts.", + "default": "compiled", + "type": "promptString" } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 1722442d..b0968948 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,11 +9,27 @@ "powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationForFirstPipeline", "powershell.codeFormatting.useConstantStrings": true, "powershell.codeFormatting.useCorrectCasing": true, - "powershell.codeFormatting.whitespaceAfterSeparator": false, + "powershell.codeFormatting.whitespaceAfterSeparator": true, "powershell.codeFormatting.whitespaceBetweenParameters": true, "powershell.codeFormatting.whitespaceInsideBrace": true, "powershell.pester.codeLens": false, "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1", - "poshProTools.ignoredPaths": "compiled", - "pester.testFilePath": ["tests/*.[tT]ests.[pP][sS]1"] + "poshProTools.ignoredPaths": "compiled/*", + "markiscodecoverage.searchCriteria": "tests\\Compiler\\Coverage\\coverage.info", + "markiscodecoverage.enableDecorations": true, + "poshProTools.disableNewsNotification": true, + "poshProTools.toolbar.formDesigner": false, + "poshProTools.toolbar.packageAsExecutable": false, + "poshProTools.toolbar.quickScripts": false, + "editor.rulers": [ + 80, + 120, + 130 + ], + "files.eol": "\n", + "path-intellisense.autoSlashAfterDirectory": true, + "path-intellisense.autoTriggerNextSuggestion": true, + "powershell.analyzeOpenDocumentsOnly": true, + "powershell.developer.editorServicesLogLevel": "Diagnostic", + "powershell.integratedConsole.suppressStartupBanner": true } diff --git a/.vscode/snippets.code-snippets b/.vscode/snippets.code-snippets index 853e8499..73a74920 100644 --- a/.vscode/snippets.code-snippets +++ b/.vscode/snippets.code-snippets @@ -34,7 +34,7 @@ "scope": "powershell", "prefix": "run", "body": [ - "Import-Module \\$PSScriptRoot/${1:Path/To/src}/common/00-Environment.psm1;", + "Import-Module \\$PSScriptRoot/${1:Path/To/src}/common/Environment.psm1;", "", "Invoke-RunMain \\$MyInvocation {", "", diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..e8217cdf --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,153 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/scripts.sln", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/scripts.sln", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/scripts.sln" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "Generate coverage stats", + "command": "dotnet", + "type": "shell", + "args": [ + "test", + "--collect:\\\"XPlat Code Coverage\\\"", + "/p:CollectCoverage=true", + "/p:CoverletOutput=Coverage/", + "/p:CoverletOutputFormat=lcov" + ], + "problemMatcher": [] + }, + { + "label": "Generate coverage report", + "command": "reportgenerator", + "type": "shell", + "args": [ + "-reports:./tests/Compiler/TestResults/**/coverage.cobertura.xml", + "-targetdir:coverage_report", + "-assemblyfilters:'+Compiler;-Compiler.Test'", + "-classfilters:'-System.Text.RegularExpressions.Generated*'" + ], + "dependsOn": [ + "Generate coverage stats" + ], + "problemMatcher": [] + }, + { + "label": "Open Coverage Report", + "dependsOn": [ + "Generate coverage report" + ], + "type": "shell", + "command": ".\\coverage_report\\index.html", + "problemMatcher": [] + }, + { + "label": "Compile Scripts", + "dependsOn": [ + "build" + ], + "command": "${workspaceFolder}/src/Compiler/bin/Debug/Compiler.exe", + "args": [ + "-i", + "${input:sourceDirectory}/${input:scriptSubdirectory}", + "-o", + "${input:outputDirectory}/${input:scriptSubdirectory}", + "-f", + "-vvv" + ], + "problemMatcher": { + "fileLocation": "absolute", + "source": "Compiler Analyser", + "pattern": [ + { + "regexp": "^File\\s\\|\\s([:\\\\\\\/\\w\\s\\._!#()-]+)$", + "file": 1, + "kind": "location", + }, + { + "regexp": "^Where\\|\\s\\((\\d+)\\[(\\d+)\\]\\)[\\.]{2}\\((\\d+)\\[(\\d+)\\]\\)$", + "line": 1, + "column": 2, + "endLine": 3, + "endColumn": 4 + }, + { + "regexp": "[\\d\\s]*\\|\\s*.+$", + }, + { + "regexp": "\\s*\\|[\\s~]+$", + }, + { + "regexp": "\\s*\\|\\s(.+)$", + "message": 1 + } + ], + "severity": "error", + "applyTo": "allDocuments" + }, + "group": "none", + "presentation": { + "echo": true, + "reveal": "silent", + "focus": false, + "panel": "dedicated", + "showReuseMessage": false, + "clear": true, + "revealProblems": "onProblem" + } + } + ], + "inputs": [ + { + "id": "sourceDirectory", + "description": "The source directory containing the scripts to compile.", + "default": "${workspaceFolder}/src", + "type": "promptString" + }, + { + "id": "outputDirectory", + "description": "The output directory for the compiled scripts.", + "default": "${workspaceFolder}/compiled2", + "type": "promptString" + }, + { + "id": "scriptSubdirectory", + "description": "A subdirectory of specific scripts relative to the source directory.", + "default": "", + "type": "promptString" + } + ] +} diff --git a/CONTRIBUTING b/CONTRIBUTING new file mode 100644 index 00000000..9ec507c1 --- /dev/null +++ b/CONTRIBUTING @@ -0,0 +1,157 @@ +# Contributing to AMTSupport Scripts + +- [Getting Started](#getting-started) +- [Security Vulnerability?](#how-to-report-a-security-vulnerability) +- [Git Commit Guidelines](#commit-message-format) + +## Getting Started + +1. **Fork the Repository** + - Click the "Fork" button at the top right of the repository page to create your own copy. + +2. **Clone Your Fork** + - Clone your forked repository to your local machine: + + ```bash + git clone https://github.com/your-username/repository-name.git + ``` + + - Replace `your-username` and `repository-name` with your GitHub username and the name of the repository. + +3. **Navigate to the Project Directory** + + ```bash + cd repository-name + ``` + +4. **Set Up the Environment** + - Required tools: + - PowerShell Core & Desktop + - .NET Core SDK + - Visual Studio Code (or any other code editor) + - Ensure that SymLink is enabled in your git configuration: + + ```bash + git config --global core.symlinks true + ``` + + - Dotnet tools: + + ```bash + dotnet install tool -g reportgenerator + ``` + +5. **Create a New Branch** + - Create a new branch for your feature or bug fix: + + ```bash + git checkout -b your-branch-name + ``` + +6. **Make Your Changes** + - Implement your changes and ensure they follow the project's coding standards. + +7. **Commit Your Changes** + - Commit your changes with a descriptive message: + + ```bash + git commit -m "chore(Compiler): cleanup unused imports" + ``` + +8. **Push to Your Fork** + - Push your changes to your forked repository: + + ```bash + git push origin your-branch-name + ``` + +9. **Create a Pull Request** + - Go to the original repository and click on "New Pull Request". Select your branch and submit the pull request. + +## Code of Conduct + +Please adhere to the [Code of Conduct](CODE_OF_CONDUCT.md) in all interactions. + +## How to report a security vulnerability + + If you find a security vulnerability, do NOT open an issue. Email instead. + Any security issues should be submitted directly to + + In order to determine whether you are dealing with a security issue, ask yourself these two questions: + +- Can I access something that's not mine, or something I shouldn't have access to? +- Can I disable something for other people? + + If the answer to either of those two questions are "yes", then you're probably dealing with a security issue. Note that even if you answer "no" to both questions, you may still be dealing with a security issue, so if you're unsure, just email me at . + +## Conventions + + + +## Git Commit Guidelines + +We have very precise rules over how our git commit messages can be formatted. This leads to **more +readable messages** that are easy to follow when looking through the **project history**. + + + +### Commit Message Format + +Each commit message consists of a **header**, a **body** and a **footer**. The header has a special +format that includes a **type**, a **scope**, and a **subject**: + +```html +(): + + + +