diff --git a/.editorconfig b/.editorconfig index 2b1039ae..3baf9fec 100644 --- a/.editorconfig +++ b/.editorconfig @@ -23,6 +23,55 @@ indent_size = 8 [*.{cs,csx,cake}] charset = utf-8-bom +# Visual Basic files +[*.{vb,vbx}] +end_of_line = crlf +charset = utf-8-bom + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,props,targets}] +indent_size = 2 + +# XML config files +[*.{ruleset,config,nuspec,resx,vsixmanifest,vsct,runsettings}] +indent_size = 2 + +# Other XML files +[*.{xml,svg}] +indent_size = 2 + +# JSON files +[*.{json,jsonc}] +indent_size = 2 + +# YAML files +[*.{yml,yaml}] +indent_size = 2 + +# Shell scripts +[*.{in,sh}] +indent_size = 2 + +# Windows batch files +[*.{bat,cmd}] +end_of_line = crlf + +# Markdown files +[*.{md,markdown}] +indent_size = 2 +trim_trailing_whitespace = false + +# InnoSetup files +[*.iss] +end_of_line = crlf +indent_size = 2 + +################################################################################ +# STATIC ANALYSIS CONFIGURATION +################################################################################ + +[*.{cs,csx,cake}] + #### .NET Coding Conventions #### dotnet_style_operator_placement_when_wrapping = beginning_of_line:suggestion @@ -241,47 +290,261 @@ dotnet_naming_style.begins_with_i.required_suffix = dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case -### *** END - C# files *** - -# Visual Basic files -[*.{vb,vbx}] -end_of_line = crlf -charset = utf-8-bom - -# XML project files -[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,props,targets}] -indent_size = 2 - -# XML config files -[*.{ruleset,config,nuspec,resx,vsixmanifest,vsct,runsettings}] -indent_size = 2 - -# Other XML files -[*.{xml,svg}] -indent_size = 2 - -# JSON files -[*.{json,jsonc}] -indent_size = 2 - -# YAML files -[*.{yml,yaml}] -indent_size = 2 - -# Shell scripts -[*.{in,sh}] -indent_size = 2 - -# Windows batch files -[*.{bat,cmd}] -end_of_line = crlf - -# Markdown files -[*.{md,markdown}] -indent_size = 2 -trim_trailing_whitespace = false - -# InnoSetup files -[*.iss] -end_of_line = crlf -indent_size = 2 +### Miscellaneous code analysis configuration + +# Relaxed rules related to IDisposable implementation - https://blog.stephencleary.com/2009/08/how-to-implement-idisposable-and.html +dotnet_diagnostic.CA1063.severity = none # CA1063: Implement IDisposable correctly +dotnet_diagnostic.CA1816.severity = none # CA1816: Call GC.SuppressFinalize correctly + +# Disable CA1508 (false positive when a value is set inside a catch block) +dotnet_diagnostic.CA1508.severity = none # CA1508: Avoid dead conditional code + +# Rules stricter than the default +dotnet_diagnostic.CA1001.severity = warning # CA1001: Types that own disposable fields should be disposable +dotnet_diagnostic.CA1047.severity = warning # CA1047: Do not declare protected members in sealed types +dotnet_diagnostic.CA1070.severity = warning # CA1070: Do not declare event fields as virtual +dotnet_diagnostic.CA2000.severity = warning # CA2000: Dispose objects before losing scope +dotnet_diagnostic.IDE0043.severity = error # IDE0043: Format string contains invalid placeholder +dotnet_diagnostic.IDE0076.severity = warning # IDE0076: Remove invalid global 'SuppressMessageAttribute' +dotnet_diagnostic.IDE0077.severity = warning # IDE0077: Avoid legacy format target in global 'SuppressMessageAttribute' + +# Miscellaneous relaxations +dotnet_diagnostic.CA1000.severity = none # CA1000: Do not declare static members on generic types +dotnet_diagnostic.CA1032.severity = suggestion # CA1032: Implement standard exception constructors +dotnet_diagnostic.CA1303.severity = none # CA1303: Do not pass literals as localized parameters + +# Miscellaneous configuration +dotnet_code_quality.CA1303.use_naming_heuristic = false # Don't raise CA1303 just because a parameter name contains Text, Message, or Caption. +dotnet_code_quality.CA1062.exclude_extension_method_this_parameter = true # Extension methods: null check may be skipped on "this" parameter. +dotnet_code_quality.CA1062.null_check_validation_methods = System.String.IsNullOrEmpty|System.String.IsNullOrWhiteSpace +dotnet_code_quality.dispose_ownership_transfer_at_constructor = true # Disposables passed to a constructor must be disposed by the constructed object. + +### StyleCop Analyzers rules + +# StyleCop Analyzers - Special rules +dotnet_diagnostic.SA0001.severity = warning # XML comment analysis disabled +dotnet_diagnostic.SA0002.severity = warning # Invalid settings file + +# StyleCop Analyzers - Spacing rules +dotnet_diagnostic.SA1000.severity = warning # Keywords should be spaced correctly +dotnet_diagnostic.SA1001.severity = warning # Commas should be spaced correctly +dotnet_diagnostic.SA1002.severity = warning # Semicolons should be spaced correctly +dotnet_diagnostic.SA1003.severity = warning # Symbols should be spaced correctly +dotnet_diagnostic.SA1004.severity = warning # Documentation lines should begin with single space +dotnet_diagnostic.SA1005.severity = warning # Single line comments should begin with single space +dotnet_diagnostic.SA1006.severity = warning # Preprocessor keywords should not be preceded by space +dotnet_diagnostic.SA1007.severity = warning # Operator keyword should be followed by space +dotnet_diagnostic.SA1008.severity = warning # Opening parenthesis should be spaced correctly +dotnet_diagnostic.SA1009.severity = warning # Closing parenthesis should be spaced correctly +dotnet_diagnostic.SA1010.severity = warning # Opening square brackets should be spaced correctly +dotnet_diagnostic.SA1011.severity = warning # Closing square brackets should be spaced correctly +dotnet_diagnostic.SA1012.severity = warning # Opening braces should be spaced correctly +dotnet_diagnostic.SA1013.severity = warning # Closing braces should be spaced correctly +dotnet_diagnostic.SA1014.severity = warning # Opening generic brackets should be spaced correctly +dotnet_diagnostic.SA1015.severity = warning # Closing generic brackets should be spaced correctly +dotnet_diagnostic.SA1016.severity = warning # Opening attribute brackets should be spaced correctly +dotnet_diagnostic.SA1017.severity = warning # Closing attribute brackets should be spaced correctly +dotnet_diagnostic.SA1018.severity = warning # Nullable type symbols should be spaced correctly +dotnet_diagnostic.SA1019.severity = warning # Member access symbols should be spaced correctly +dotnet_diagnostic.SA1020.severity = warning # Increment decrement symbols should be spaced correctly +dotnet_diagnostic.SA1021.severity = warning # Negative signs should be spaced correctly +dotnet_diagnostic.SA1022.severity = warning # Positive signs should be spaced correctly +dotnet_diagnostic.SA1023.severity = warning # Dereference and access of symbols should be spaced correctly +dotnet_diagnostic.SA1024.severity = warning # Colons should be spaced correctly +dotnet_diagnostic.SA1025.severity = warning # Code should not contain multiple whitespace in a row +dotnet_diagnostic.SA1026.severity = warning # Code should not contain space after new or stackalloc keyword in implicitly typed array allocation +dotnet_diagnostic.SA1027.severity = warning # Use tabs correctly +dotnet_diagnostic.SA1028.severity = warning # Code should not contain trailing whitespace + +# StyleCop Analyzers - Readability rules +dotnet_diagnostic.SA1100.severity = warning # Do not prefix calls with base unless local implementation exists +dotnet_diagnostic.SA1101.severity = none # Prefix local calls with this +dotnet_diagnostic.SX1101.severity = warning # Do not prefix local calls with this +dotnet_diagnostic.SA1102.severity = warning # Query clause should follow previous clause +dotnet_diagnostic.SA1103.severity = warning # Query clauses should be on separate lines or all on one line +dotnet_diagnostic.SA1104.severity = warning # Query clause should begin on new line when previous clause spans multiple lines +dotnet_diagnostic.SA1105.severity = warning # Query clauses spanning multiple lines should begin on own line +dotnet_diagnostic.SA1106.severity = warning # Code should not contain empty statements +dotnet_diagnostic.SA1107.severity = warning # Code should not contain multiple statements on one line +dotnet_diagnostic.SA1108.severity = warning # Block statements should not contain embedded comments +dotnet_diagnostic.SA1109.severity = warning # Block statements should not contain embedded regions +dotnet_diagnostic.SA1110.severity = warning # Opening parenthesis or bracket should be on declaration line +dotnet_diagnostic.SA1111.severity = warning # Closing parenthesis should be on line of last parameter +dotnet_diagnostic.SA1112.severity = warning # Closing parenthesis should be on line of opening parenthesis +dotnet_diagnostic.SA1113.severity = warning # Comma should be on the same line as previous parameter +dotnet_diagnostic.SA1114.severity = warning # Parameter list should follow declaration +dotnet_diagnostic.SA1115.severity = warning # Parameter should follow comma +dotnet_diagnostic.SA1116.severity = warning # Split parameters should start on line after declaration +dotnet_diagnostic.SA1117.severity = warning # Parameters should be on same line or separate lines +dotnet_diagnostic.SA1118.severity = warning # Parameter should not span multiple lines +dotnet_diagnostic.SA1120.severity = warning # Comments should contain text +dotnet_diagnostic.SA1121.severity = warning # Use built-in type alias +dotnet_diagnostic.SA1122.severity = warning # Use string.Empty for empty strings +dotnet_diagnostic.SA1123.severity = warning # Do not place regions within elements +dotnet_diagnostic.SA1124.severity = warning # Do not use regions +dotnet_diagnostic.SA1125.severity = warning # Use shorthand for nullable types +dotnet_diagnostic.SA1126.severity = warning # Prefix calls correctly +dotnet_diagnostic.SA1127.severity = warning # Generic type constraints should be on their own line +dotnet_diagnostic.SA1128.severity = warning # Put constructor initializers on their own line +dotnet_diagnostic.SA1129.severity = warning # Do not use default value type constructor +dotnet_diagnostic.SA1130.severity = warning # Use lambda syntax +dotnet_diagnostic.SA1131.severity = warning # Use readable conditions +dotnet_diagnostic.SA1132.severity = warning # Do not combine fields +dotnet_diagnostic.SA1133.severity = warning # Do not combine attributes +dotnet_diagnostic.SA1134.severity = warning # Attributes should not share line +dotnet_diagnostic.SA1135.severity = warning # Using directives should be qualified +dotnet_diagnostic.SA1136.severity = warning # Enum values should be on separate lines +dotnet_diagnostic.SA1137.severity = warning # Elements should have the same indentation +dotnet_diagnostic.SA1139.severity = warning # Use literal suffix notation instead of casting + +# StyleCop Analyzers - Ordering rules +dotnet_diagnostic.SA1200.severity = warning # Using directives should be placed correctly +dotnet_diagnostic.SA1201.severity = warning # Elements should appear in the correct order +dotnet_diagnostic.SA1202.severity = warning # Elements should be ordered by access +dotnet_diagnostic.SA1203.severity = warning # Constants should appear before fields +dotnet_diagnostic.SA1204.severity = warning # Static elements should appear before instance elements +dotnet_diagnostic.SA1205.severity = none # Partial elements should declare access +dotnet_diagnostic.SA1206.severity = warning # Declaration keywords should follow order +dotnet_diagnostic.SA1207.severity = warning # Protected should come before internal +dotnet_diagnostic.SA1208.severity = warning # System using directives should be placed before other using directives +dotnet_diagnostic.SA1209.severity = warning # Using alias directives should be placed after other using directives +dotnet_diagnostic.SA1210.severity = warning # Using directives should be ordered alphabetically by namespace +dotnet_diagnostic.SA1211.severity = warning # Using alias directives should be ordered alphabetically by alias name +dotnet_diagnostic.SA1212.severity = warning # Property accessors should follow order +dotnet_diagnostic.SA1213.severity = warning # Event accessors should follow order +dotnet_diagnostic.SA1214.severity = warning # Readonly fields should appear before non-readonly fields +dotnet_diagnostic.SA1216.severity = warning # Using static directives should be placed at the correct location +dotnet_diagnostic.SA1217.severity = warning # Using static directives should be ordered alphabetically + +# StyleCop Analyzers - Naming rules +dotnet_diagnostic.SA1300.severity = warning # Element should begin with upper-case letter +dotnet_diagnostic.SA1301.severity = warning # Element should begin with lower-case letter +dotnet_diagnostic.SA1302.severity = warning # Interface names should begin with I +dotnet_diagnostic.SA1303.severity = warning # Const field names should begin with upper-case letter +dotnet_diagnostic.SA1304.severity = warning # Non-private readonly fields should begin with upper-case letter +dotnet_diagnostic.SA1305.severity = none # Field names should not use Hungarian notation +dotnet_diagnostic.SA1306.severity = warning # Field names should begin with lower-case letter +dotnet_diagnostic.SA1307.severity = warning # Accessible fields should begin with upper-case letter +dotnet_diagnostic.SA1308.severity = warning # Variable names should not be prefixed +dotnet_diagnostic.SA1309.severity = none # Private instance field names should not begin with underscore +dotnet_diagnostic.SX1309.severity = warning # Private instance field names should begin with underscore +dotnet_diagnostic.SX1309S.severity = none # Static field names should begin with underscore +dotnet_diagnostic.SA1310.severity = warning # Field names should not contain underscore +dotnet_diagnostic.SA1311.severity = warning # Static readonly fields should begin with upper-case letter +dotnet_diagnostic.SA1312.severity = warning # Variable names should begin with lower-case letter +dotnet_diagnostic.SA1313.severity = warning # Parameter names should begin with lower-case letter +dotnet_diagnostic.SA1314.severity = warning # Type parameter names should begin with T + +# StyleCop Analyzers - Maintainability rules +dotnet_diagnostic.SA1119.severity = warning # Statement should not use unnecessary parenthesis +dotnet_diagnostic.SA1400.severity = warning # Access modifier should be declared +dotnet_diagnostic.SA1401.severity = warning # Fields should be private +dotnet_diagnostic.SA1402.severity = warning # File may only contain a single type +dotnet_diagnostic.SA1403.severity = warning # File may only contain a single namespace +dotnet_diagnostic.SA1404.severity = warning # Code analysis suppression should have justification +dotnet_diagnostic.SA1405.severity = warning # Debug.Assert should provide message text +dotnet_diagnostic.SA1406.severity = warning # Debug.Fail should provide message text +dotnet_diagnostic.SA1407.severity = none # Arithmetic expressions should declare precedence +dotnet_diagnostic.SA1408.severity = warning # Conditional expressions should declare precedence +dotnet_diagnostic.SA1409.severity = none # Remove unnecessary code +dotnet_diagnostic.SA1410.severity = warning # Remove delegate parenthesis when possible +dotnet_diagnostic.SA1411.severity = warning # Attribute constructor should not use unnecessary parenthesis +dotnet_diagnostic.SA1412.severity = warning # Store files as UTF-8 with byte order mark +dotnet_diagnostic.SA1413.severity = warning # Use trailing comma in multi-line initializers + +# StyleCop Analyzers - Layout rules +dotnet_diagnostic.SA1500.severity = warning # Braces for multi-line statements should not share line +dotnet_diagnostic.SA1501.severity = warning # Statement should not be on a single line +dotnet_diagnostic.SA1502.severity = warning # Element should not be on a single line +dotnet_diagnostic.SA1503.severity = warning # Braces should not be omitted +dotnet_diagnostic.SA1504.severity = warning # All accessors should be single-line or multi-line +dotnet_diagnostic.SA1505.severity = warning # Opening braces should not be followed by blank line +dotnet_diagnostic.SA1506.severity = warning # Element documentation headers should not be followed by blank line +dotnet_diagnostic.SA1507.severity = warning # Code should not contain multiple blank lines in a row +dotnet_diagnostic.SA1508.severity = warning # Closing braces should not be preceded by blank line +dotnet_diagnostic.SA1509.severity = warning # Opening braces should not be preceded by blank line +dotnet_diagnostic.SA1510.severity = warning # Chained statement blocks should not be preceded by blank line +dotnet_diagnostic.SA1511.severity = warning # While-do footer should not be preceded by blank line +dotnet_diagnostic.SA1512.severity = warning # Single-line comments should not be followed by blank line +dotnet_diagnostic.SA1513.severity = warning # Closing brace should be followed by blank line +dotnet_diagnostic.SA1514.severity = warning # Element documentation header should be preceded by blank line +dotnet_diagnostic.SA1515.severity = warning # Single-line comment should be preceded by blank line +dotnet_diagnostic.SA1516.severity = none # Elements should be separated by blank line +dotnet_diagnostic.SA1517.severity = warning # Code should not contain blank lines at start of file +dotnet_diagnostic.SA1518.severity = warning # Use line endings correctly at end of file +dotnet_diagnostic.SA1519.severity = warning # Braces should not be omitted from multi-line child statement +dotnet_diagnostic.SA1520.severity = warning # Use braces consistently + +# StyleCop Analyzers - Documentation rules +dotnet_diagnostic.SA1600.severity = warning # Elements should be documented +dotnet_diagnostic.SA1601.severity = none # Partial elements should be documented +dotnet_diagnostic.SA1602.severity = warning # Enumeration items should be documented +dotnet_diagnostic.SA1603.severity = warning # Documentation should contain valid XML +dotnet_diagnostic.SA1604.severity = warning # Element documentation should have summary +dotnet_diagnostic.SA1605.severity = warning # Partial element documentation should have summary +dotnet_diagnostic.SA1606.severity = warning # Element documentation should have summary text +dotnet_diagnostic.SA1607.severity = warning # Partial element documentation should have summary text +dotnet_diagnostic.SA1608.severity = warning # Element documentation should not have default summary +dotnet_diagnostic.SA1609.severity = none # Property documentation should have value +dotnet_diagnostic.SA1610.severity = none # Property documentation should have value text +dotnet_diagnostic.SA1611.severity = warning # Element parameters should be documented +dotnet_diagnostic.SA1612.severity = warning # Element parameter documentation should match element parameters +dotnet_diagnostic.SA1613.severity = warning # Element parameter documentation should declare parameter name +dotnet_diagnostic.SA1614.severity = warning # Element parameter documentation should have text +dotnet_diagnostic.SA1615.severity = warning # Element return value should be documented +dotnet_diagnostic.SA1616.severity = warning # Element return value documentation should have text +dotnet_diagnostic.SA1617.severity = warning # Void return value should not be documented +dotnet_diagnostic.SA1618.severity = warning # Generic type parameters should be documented +dotnet_diagnostic.SA1619.severity = warning # Generic type parameters should be documented partial class +dotnet_diagnostic.SA1620.severity = warning # Generic type parameter documentation should match type parameters +dotnet_diagnostic.SA1621.severity = warning # Generic type parameter documentation should declare parameter name +dotnet_diagnostic.SA1622.severity = warning # Generic type parameter documentation should have text +dotnet_diagnostic.SA1623.severity = warning # Property summary documentation should match accessors +dotnet_diagnostic.SA1624.severity = warning # Property summary documentation should omit accessor with restricted access +dotnet_diagnostic.SA1625.severity = warning # Element documentation should not be copied and pasted +dotnet_diagnostic.SA1626.severity = warning # Single-line comments should not use documentation style slashes +dotnet_diagnostic.SA1627.severity = warning # Documentation text should not be empty +dotnet_diagnostic.SA1628.severity = warning # Documentation text should begin with a capital letter +dotnet_diagnostic.SA1629.severity = warning # Documentation text should end with a period +dotnet_diagnostic.SA1630.severity = warning # Documentation text should contain whitespace +dotnet_diagnostic.SA1631.severity = none # Documentation should meet character percentage +dotnet_diagnostic.SA1632.severity = none # Documentation text should meet minimum character length +dotnet_diagnostic.SA1633.severity = warning # File should have header +dotnet_diagnostic.SA1634.severity = warning # File header should show copyright +dotnet_diagnostic.SA1635.severity = warning # File header should have copyright text +dotnet_diagnostic.SA1636.severity = warning # File header copyright text should match +dotnet_diagnostic.SA1637.severity = warning # File header should contain file name +dotnet_diagnostic.SA1638.severity = warning # File header file name documentation should match file name +dotnet_diagnostic.SA1639.severity = warning # File header should have summary +dotnet_diagnostic.SA1640.severity = warning # File header should have valid company text +dotnet_diagnostic.SA1641.severity = warning # File header company name text should match +dotnet_diagnostic.SA1642.severity = warning # Constructor summary documentation should begin with standard text +dotnet_diagnostic.SA1643.severity = warning # Destructor summary documentation should begin with standard text +dotnet_diagnostic.SA1644.severity = warning # Documentation headers should not contain blank lines +dotnet_diagnostic.SA1645.severity = warning # Included documentation file does not exist +dotnet_diagnostic.SA1646.severity = warning # Included documentation XPath does not exist +dotnet_diagnostic.SA1647.severity = warning # Include node does not contain valid file and path +dotnet_diagnostic.SA1648.severity = warning # Inheritdoc should be used with inheriting class +dotnet_diagnostic.SA1649.severity = warning # File name should match first type name +dotnet_diagnostic.SA1650.severity = warning # Element documentation should be spelled correctly +dotnet_diagnostic.SA1651.severity = warning # Do not use placeholder elements + +# Suppress some annoying IDE messages +dotnet_diagnostic.IDE0040.severity = none # Accessibility modifiers required - has confusing rules and is a dupe of SA1400. +dotnet_diagnostic.IDE0079.severity = none # Remove unnecessary suppression - apparently VS (as of v17.3.0) deems way too much stuff "unnecessary". +dotnet_diagnostic.IDE0290.severity = none # Use primary constructor - No. Just no. + +# Solution-specific overrides + +# Some types and memberts are unused but present for completeness and/or future use, or instantiated via DI. +# We don't need to flag every unused type or member: sprinkling PublicAPI and/or UsedImplicitly attributes around would be mostly noise. +resharper_class_never_instantiated_global_highlighting = none +resharper_unused_type_global_highlighting = none +resharper_unused_member_global_highlighting = none +resharper_member_can_be_private_global_highlighting = none + +# Given the type of C# projects (compiled MSBuild tasks, CLI tool) we don't need to optimize logging with LoggerMessage delegates (CA1848), +# nor do we need CA1873 to complain that "argument evaluation may be expensive when logging is disabled". +# Disabling these rules globally helps keep code clean and simple without needing to sprinkle pragmas or suppression attributes around the codebase. +dotnet_diagnostic.CA1848.severity = none +dotnet_diagnostic.CA1873.severity = none diff --git a/.globalconfig b/.globalconfig deleted file mode 100644 index d4788a63..00000000 --- a/.globalconfig +++ /dev/null @@ -1,262 +0,0 @@ -# Global AnalyzerConfig file -# See https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/configuration-files#global-analyzerconfig - -is_global = true - -### Miscellaneous code analysis configuration - -# Relaxed rules related to IDisposable implementation - https://blog.stephencleary.com/2009/08/how-to-implement-idisposable-and.html -dotnet_diagnostic.CA1063.severity = none # CA1063: Implement IDisposable correctly -dotnet_diagnostic.CA1816.severity = none # CA1816: Call GC.SuppressFinalize correctly - -# Disable CA1508 (false positive when a value is set inside a catch block) -dotnet_diagnostic.CA1508.severity = none # CA1508: Avoid dead conditional code - -# Rules stricter than the default -dotnet_diagnostic.CA1001.severity = warning # CA1001: Types that own disposable fields should be disposable -dotnet_diagnostic.CA1047.severity = warning # CA1047: Do not declare protected members in sealed types -dotnet_diagnostic.CA1070.severity = warning # CA1070: Do not declare event fields as virtual -dotnet_diagnostic.CA2000.severity = warning # CA2000: Dispose objects before losing scope -dotnet_diagnostic.IDE0043.severity = error # IDE0043: Format string contains invalid placeholder -dotnet_diagnostic.IDE0076.severity = warning # IDE0076: Remove invalid global 'SuppressMessageAttribute' -dotnet_diagnostic.IDE0077.severity = warning # IDE0077: Avoid legacy format target in global 'SuppressMessageAttribute' - -# Miscellaneous relaxations -dotnet_diagnostic.CA1000.severity = none # CA1000: Do not declare static members on generic types -dotnet_diagnostic.CA1032.severity = suggestion # CA1032: Implement standard exception constructors -dotnet_diagnostic.CA1303.severity = none # CA1303: Do not pass literals as localized parameters - -# Miscellaneous configuration -dotnet_code_quality.CA1303.use_naming_heuristic = false # Don't raise CA1303 just because a parameter name contains Text, Message, or Caption. -dotnet_code_quality.CA1062.exclude_extension_method_this_parameter = true # Extension methods: null check may be skipped on "this" parameter. -dotnet_code_quality.CA1062.null_check_validation_methods = System.String.IsNullOrEmpty|System.String.IsNullOrWhiteSpace -dotnet_code_quality.dispose_ownership_transfer_at_constructor = true # Disposables passed to a constructor must be disposed by the constructed object. - -### StyleCop Analyzers rules - -# StyleCop Analyzers - Special rules -dotnet_diagnostic.SA0001.severity = warning # XML comment analysis disabled -dotnet_diagnostic.SA0002.severity = warning # Invalid settings file - -# StyleCop Analyzers - Spacing rules -dotnet_diagnostic.SA1000.severity = warning # Keywords should be spaced correctly -dotnet_diagnostic.SA1001.severity = warning # Commas should be spaced correctly -dotnet_diagnostic.SA1002.severity = warning # Semicolons should be spaced correctly -dotnet_diagnostic.SA1003.severity = warning # Symbols should be spaced correctly -dotnet_diagnostic.SA1004.severity = warning # Documentation lines should begin with single space -dotnet_diagnostic.SA1005.severity = warning # Single line comments should begin with single space -dotnet_diagnostic.SA1006.severity = warning # Preprocessor keywords should not be preceded by space -dotnet_diagnostic.SA1007.severity = warning # Operator keyword should be followed by space -dotnet_diagnostic.SA1008.severity = warning # Opening parenthesis should be spaced correctly -dotnet_diagnostic.SA1009.severity = warning # Closing parenthesis should be spaced correctly -dotnet_diagnostic.SA1010.severity = warning # Opening square brackets should be spaced correctly -dotnet_diagnostic.SA1011.severity = warning # Closing square brackets should be spaced correctly -dotnet_diagnostic.SA1012.severity = warning # Opening braces should be spaced correctly -dotnet_diagnostic.SA1013.severity = warning # Closing braces should be spaced correctly -dotnet_diagnostic.SA1014.severity = warning # Opening generic brackets should be spaced correctly -dotnet_diagnostic.SA1015.severity = warning # Closing generic brackets should be spaced correctly -dotnet_diagnostic.SA1016.severity = warning # Opening attribute brackets should be spaced correctly -dotnet_diagnostic.SA1017.severity = warning # Closing attribute brackets should be spaced correctly -dotnet_diagnostic.SA1018.severity = warning # Nullable type symbols should be spaced correctly -dotnet_diagnostic.SA1019.severity = warning # Member access symbols should be spaced correctly -dotnet_diagnostic.SA1020.severity = warning # Increment decrement symbols should be spaced correctly -dotnet_diagnostic.SA1021.severity = warning # Negative signs should be spaced correctly -dotnet_diagnostic.SA1022.severity = warning # Positive signs should be spaced correctly -dotnet_diagnostic.SA1023.severity = warning # Dereference and access of symbols should be spaced correctly -dotnet_diagnostic.SA1024.severity = warning # Colons should be spaced correctly -dotnet_diagnostic.SA1025.severity = warning # Code should not contain multiple whitespace in a row -dotnet_diagnostic.SA1026.severity = warning # Code should not contain space after new or stackalloc keyword in implicitly typed array allocation -dotnet_diagnostic.SA1027.severity = warning # Use tabs correctly -dotnet_diagnostic.SA1028.severity = warning # Code should not contain trailing whitespace - -# StyleCop Analyzers - Readability rules -dotnet_diagnostic.SA1100.severity = warning # Do not prefix calls with base unless local implementation exists -dotnet_diagnostic.SA1101.severity = none # Prefix local calls with this -dotnet_diagnostic.SX1101.severity = warning # Do not prefix local calls with this -dotnet_diagnostic.SA1102.severity = warning # Query clause should follow previous clause -dotnet_diagnostic.SA1103.severity = warning # Query clauses should be on separate lines or all on one line -dotnet_diagnostic.SA1104.severity = warning # Query clause should begin on new line when previous clause spans multiple lines -dotnet_diagnostic.SA1105.severity = warning # Query clauses spanning multiple lines should begin on own line -dotnet_diagnostic.SA1106.severity = warning # Code should not contain empty statements -dotnet_diagnostic.SA1107.severity = warning # Code should not contain multiple statements on one line -dotnet_diagnostic.SA1108.severity = warning # Block statements should not contain embedded comments -dotnet_diagnostic.SA1109.severity = warning # Block statements should not contain embedded regions -dotnet_diagnostic.SA1110.severity = warning # Opening parenthesis or bracket should be on declaration line -dotnet_diagnostic.SA1111.severity = warning # Closing parenthesis should be on line of last parameter -dotnet_diagnostic.SA1112.severity = warning # Closing parenthesis should be on line of opening parenthesis -dotnet_diagnostic.SA1113.severity = warning # Comma should be on the same line as previous parameter -dotnet_diagnostic.SA1114.severity = warning # Parameter list should follow declaration -dotnet_diagnostic.SA1115.severity = warning # Parameter should follow comma -dotnet_diagnostic.SA1116.severity = warning # Split parameters should start on line after declaration -dotnet_diagnostic.SA1117.severity = warning # Parameters should be on same line or separate lines -dotnet_diagnostic.SA1118.severity = warning # Parameter should not span multiple lines -dotnet_diagnostic.SA1120.severity = warning # Comments should contain text -dotnet_diagnostic.SA1121.severity = warning # Use built-in type alias -dotnet_diagnostic.SA1122.severity = warning # Use string.Empty for empty strings -dotnet_diagnostic.SA1123.severity = warning # Do not place regions within elements -dotnet_diagnostic.SA1124.severity = warning # Do not use regions -dotnet_diagnostic.SA1125.severity = warning # Use shorthand for nullable types -dotnet_diagnostic.SA1126.severity = warning # Prefix calls correctly -dotnet_diagnostic.SA1127.severity = warning # Generic type constraints should be on their own line -dotnet_diagnostic.SA1128.severity = warning # Put constructor initializers on their own line -dotnet_diagnostic.SA1129.severity = warning # Do not use default value type constructor -dotnet_diagnostic.SA1130.severity = warning # Use lambda syntax -dotnet_diagnostic.SA1131.severity = warning # Use readable conditions -dotnet_diagnostic.SA1132.severity = warning # Do not combine fields -dotnet_diagnostic.SA1133.severity = warning # Do not combine attributes -dotnet_diagnostic.SA1134.severity = warning # Attributes should not share line -dotnet_diagnostic.SA1135.severity = warning # Using directives should be qualified -dotnet_diagnostic.SA1136.severity = warning # Enum values should be on separate lines -dotnet_diagnostic.SA1137.severity = warning # Elements should have the same indentation -dotnet_diagnostic.SA1139.severity = warning # Use literal suffix notation instead of casting - -# StyleCop Analyzers - Ordering rules -dotnet_diagnostic.SA1200.severity = warning # Using directives should be placed correctly -dotnet_diagnostic.SA1201.severity = warning # Elements should appear in the correct order -dotnet_diagnostic.SA1202.severity = warning # Elements should be ordered by access -dotnet_diagnostic.SA1203.severity = warning # Constants should appear before fields -dotnet_diagnostic.SA1204.severity = warning # Static elements should appear before instance elements -dotnet_diagnostic.SA1205.severity = none # Partial elements should declare access -dotnet_diagnostic.SA1206.severity = warning # Declaration keywords should follow order -dotnet_diagnostic.SA1207.severity = warning # Protected should come before internal -dotnet_diagnostic.SA1208.severity = warning # System using directives should be placed before other using directives -dotnet_diagnostic.SA1209.severity = warning # Using alias directives should be placed after other using directives -dotnet_diagnostic.SA1210.severity = warning # Using directives should be ordered alphabetically by namespace -dotnet_diagnostic.SA1211.severity = warning # Using alias directives should be ordered alphabetically by alias name -dotnet_diagnostic.SA1212.severity = warning # Property accessors should follow order -dotnet_diagnostic.SA1213.severity = warning # Event accessors should follow order -dotnet_diagnostic.SA1214.severity = warning # Readonly fields should appear before non-readonly fields -dotnet_diagnostic.SA1216.severity = warning # Using static directives should be placed at the correct location -dotnet_diagnostic.SA1217.severity = warning # Using static directives should be ordered alphabetically - -# StyleCop Analyzers - Naming rules -dotnet_diagnostic.SA1300.severity = warning # Element should begin with upper-case letter -dotnet_diagnostic.SA1301.severity = warning # Element should begin with lower-case letter -dotnet_diagnostic.SA1302.severity = warning # Interface names should begin with I -dotnet_diagnostic.SA1303.severity = warning # Const field names should begin with upper-case letter -dotnet_diagnostic.SA1304.severity = warning # Non-private readonly fields should begin with upper-case letter -dotnet_diagnostic.SA1305.severity = none # Field names should not use Hungarian notation -dotnet_diagnostic.SA1306.severity = warning # Field names should begin with lower-case letter -dotnet_diagnostic.SA1307.severity = warning # Accessible fields should begin with upper-case letter -dotnet_diagnostic.SA1308.severity = warning # Variable names should not be prefixed -dotnet_diagnostic.SA1309.severity = none # Private instance field names should not begin with underscore -dotnet_diagnostic.SX1309.severity = warning # Private instance field names should begin with underscore -dotnet_diagnostic.SX1309S.severity = none # Static field names should begin with underscore -dotnet_diagnostic.SA1310.severity = warning # Field names should not contain underscore -dotnet_diagnostic.SA1311.severity = warning # Static readonly fields should begin with upper-case letter -dotnet_diagnostic.SA1312.severity = warning # Variable names should begin with lower-case letter -dotnet_diagnostic.SA1313.severity = warning # Parameter names should begin with lower-case letter -dotnet_diagnostic.SA1314.severity = warning # Type parameter names should begin with T - -# StyleCop Analyzers - Maintainability rules -dotnet_diagnostic.SA1119.severity = warning # Statement should not use unnecessary parenthesis -dotnet_diagnostic.SA1400.severity = warning # Access modifier should be declared -dotnet_diagnostic.SA1401.severity = warning # Fields should be private -dotnet_diagnostic.SA1402.severity = warning # File may only contain a single type -dotnet_diagnostic.SA1403.severity = warning # File may only contain a single namespace -dotnet_diagnostic.SA1404.severity = warning # Code analysis suppression should have justification -dotnet_diagnostic.SA1405.severity = warning # Debug.Assert should provide message text -dotnet_diagnostic.SA1406.severity = warning # Debug.Fail should provide message text -dotnet_diagnostic.SA1407.severity = none # Arithmetic expressions should declare precedence -dotnet_diagnostic.SA1408.severity = warning # Conditional expressions should declare precedence -dotnet_diagnostic.SA1409.severity = none # Remove unnecessary code -dotnet_diagnostic.SA1410.severity = warning # Remove delegate parenthesis when possible -dotnet_diagnostic.SA1411.severity = warning # Attribute constructor should not use unnecessary parenthesis -dotnet_diagnostic.SA1412.severity = warning # Store files as UTF-8 with byte order mark -dotnet_diagnostic.SA1413.severity = warning # Use trailing comma in multi-line initializers - -# StyleCop Analyzers - Layout rules -dotnet_diagnostic.SA1500.severity = warning # Braces for multi-line statements should not share line -dotnet_diagnostic.SA1501.severity = warning # Statement should not be on a single line -dotnet_diagnostic.SA1502.severity = warning # Element should not be on a single line -dotnet_diagnostic.SA1503.severity = warning # Braces should not be omitted -dotnet_diagnostic.SA1504.severity = warning # All accessors should be single-line or multi-line -dotnet_diagnostic.SA1505.severity = warning # Opening braces should not be followed by blank line -dotnet_diagnostic.SA1506.severity = warning # Element documentation headers should not be followed by blank line -dotnet_diagnostic.SA1507.severity = warning # Code should not contain multiple blank lines in a row -dotnet_diagnostic.SA1508.severity = warning # Closing braces should not be preceded by blank line -dotnet_diagnostic.SA1509.severity = warning # Opening braces should not be preceded by blank line -dotnet_diagnostic.SA1510.severity = warning # Chained statement blocks should not be preceded by blank line -dotnet_diagnostic.SA1511.severity = warning # While-do footer should not be preceded by blank line -dotnet_diagnostic.SA1512.severity = warning # Single-line comments should not be followed by blank line -dotnet_diagnostic.SA1513.severity = warning # Closing brace should be followed by blank line -dotnet_diagnostic.SA1514.severity = warning # Element documentation header should be preceded by blank line -dotnet_diagnostic.SA1515.severity = warning # Single-line comment should be preceded by blank line -dotnet_diagnostic.SA1516.severity = none # Elements should be separated by blank line -dotnet_diagnostic.SA1517.severity = warning # Code should not contain blank lines at start of file -dotnet_diagnostic.SA1518.severity = warning # Use line endings correctly at end of file -dotnet_diagnostic.SA1519.severity = warning # Braces should not be omitted from multi-line child statement -dotnet_diagnostic.SA1520.severity = warning # Use braces consistently - -# StyleCop Analyzers - Documentation rules -dotnet_diagnostic.SA1600.severity = warning # Elements should be documented -dotnet_diagnostic.SA1601.severity = none # Partial elements should be documented -dotnet_diagnostic.SA1602.severity = warning # Enumeration items should be documented -dotnet_diagnostic.SA1603.severity = warning # Documentation should contain valid XML -dotnet_diagnostic.SA1604.severity = warning # Element documentation should have summary -dotnet_diagnostic.SA1605.severity = warning # Partial element documentation should have summary -dotnet_diagnostic.SA1606.severity = warning # Element documentation should have summary text -dotnet_diagnostic.SA1607.severity = warning # Partial element documentation should have summary text -dotnet_diagnostic.SA1608.severity = warning # Element documentation should not have default summary -dotnet_diagnostic.SA1609.severity = none # Property documentation should have value -dotnet_diagnostic.SA1610.severity = none # Property documentation should have value text -dotnet_diagnostic.SA1611.severity = warning # Element parameters should be documented -dotnet_diagnostic.SA1612.severity = warning # Element parameter documentation should match element parameters -dotnet_diagnostic.SA1613.severity = warning # Element parameter documentation should declare parameter name -dotnet_diagnostic.SA1614.severity = warning # Element parameter documentation should have text -dotnet_diagnostic.SA1615.severity = warning # Element return value should be documented -dotnet_diagnostic.SA1616.severity = warning # Element return value documentation should have text -dotnet_diagnostic.SA1617.severity = warning # Void return value should not be documented -dotnet_diagnostic.SA1618.severity = warning # Generic type parameters should be documented -dotnet_diagnostic.SA1619.severity = warning # Generic type parameters should be documented partial class -dotnet_diagnostic.SA1620.severity = warning # Generic type parameter documentation should match type parameters -dotnet_diagnostic.SA1621.severity = warning # Generic type parameter documentation should declare parameter name -dotnet_diagnostic.SA1622.severity = warning # Generic type parameter documentation should have text -dotnet_diagnostic.SA1623.severity = warning # Property summary documentation should match accessors -dotnet_diagnostic.SA1624.severity = warning # Property summary documentation should omit accessor with restricted access -dotnet_diagnostic.SA1625.severity = warning # Element documentation should not be copied and pasted -dotnet_diagnostic.SA1626.severity = warning # Single-line comments should not use documentation style slashes -dotnet_diagnostic.SA1627.severity = warning # Documentation text should not be empty -dotnet_diagnostic.SA1628.severity = warning # Documentation text should begin with a capital letter -dotnet_diagnostic.SA1629.severity = warning # Documentation text should end with a period -dotnet_diagnostic.SA1630.severity = warning # Documentation text should contain whitespace -dotnet_diagnostic.SA1631.severity = none # Documentation should meet character percentage -dotnet_diagnostic.SA1632.severity = none # Documentation text should meet minimum character length -dotnet_diagnostic.SA1633.severity = warning # File should have header -dotnet_diagnostic.SA1634.severity = warning # File header should show copyright -dotnet_diagnostic.SA1635.severity = warning # File header should have copyright text -dotnet_diagnostic.SA1636.severity = warning # File header copyright text should match -dotnet_diagnostic.SA1637.severity = warning # File header should contain file name -dotnet_diagnostic.SA1638.severity = warning # File header file name documentation should match file name -dotnet_diagnostic.SA1639.severity = warning # File header should have summary -dotnet_diagnostic.SA1640.severity = warning # File header should have valid company text -dotnet_diagnostic.SA1641.severity = warning # File header company name text should match -dotnet_diagnostic.SA1642.severity = warning # Constructor summary documentation should begin with standard text -dotnet_diagnostic.SA1643.severity = warning # Destructor summary documentation should begin with standard text -dotnet_diagnostic.SA1644.severity = warning # Documentation headers should not contain blank lines -dotnet_diagnostic.SA1645.severity = warning # Included documentation file does not exist -dotnet_diagnostic.SA1646.severity = warning # Included documentation XPath does not exist -dotnet_diagnostic.SA1647.severity = warning # Include node does not contain valid file and path -dotnet_diagnostic.SA1648.severity = warning # Inheritdoc should be used with inheriting class -dotnet_diagnostic.SA1649.severity = warning # File name should match first type name -dotnet_diagnostic.SA1650.severity = warning # Element documentation should be spelled correctly -dotnet_diagnostic.SA1651.severity = warning # Do not use placeholder elements - -# Suppress some annoying IDE messages -dotnet_diagnostic.IDE0040.severity = none # Accessibility modifiers required - has confusing rules and is a dupe of SA1400. -dotnet_diagnostic.IDE0079.severity = none # Remove unnecessary suppression - apparently VS (as of v17.3.0) deems way too much stuff "unnecessary". -dotnet_diagnostic.IDE0290.severity = none # Use primary constructor - No. Just no. - -# Solution-specific overrides - -# This project generates no library packages; still, public types are used via reflection and/or DI, so "unused" public types are not a concern. -resharper_class_never_instantiated_global_highlighting = none - -# Some methods are unused but present for completeness and/or future use; "unused" members are not a concern. -resharper_unused_member_global_highlighting = none - -# Given the type of C# projects (compiled MSBuild tasks, CLI tool) we don't need to optimize logging with LoggerMessage delegates (CA1848), -# nor do we need CA1873 to complain that "argument evaluation may be expensive when logging is disabled". -# Disabling these rules globally helps keep code clean and simple without needing to sprinkle pragmas or suppression attributes around the codebase. -dotnet_diagnostic.CA1848.severity = none -dotnet_diagnostic.CA1873.severity = none diff --git a/.vscode/settings.json b/.vscode/settings.json index 55ed183f..158dfa8b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -74,7 +74,8 @@ // Configure file associations to languages (e.g. "*.extension": "html"). These have precedence over the default associations of the languages installed. "files.associations": { ".globalconfig": "editorconfig", - "*.md": "markdown" + "*.md": "markdown", + "*.sarif": "json", }, // The default character set encoding to use when reading and writing files. "files.encoding": "utf8", diff --git a/Buildvana.slnx.DotSettings b/Buildvana.slnx.DotSettings index 785161b7..7e87876f 100644 --- a/Buildvana.slnx.DotSettings +++ b/Buildvana.slnx.DotSettings @@ -2,6 +2,7 @@ None NotCompiledCode True + SOLUTION DoShow DoShow DoShow @@ -424,6 +425,7 @@ WARNING DO_NOT_SHOW WARNING + ShowAndRun MergeVsActionsIntoResharperMenu Experimental LF @@ -487,6 +489,7 @@ <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"><ElementKinds><Kind Name="NAMESPACE" /><Kind Name="CLASS" /><Kind Name="STRUCT" /><Kind Name="ENUM" /><Kind Name="DELEGATE" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /></Policy> <Configurator><ConnectList /></Configurator> True + True True True True @@ -494,6 +497,7 @@ True System.CodeDom.Compiler.GeneratedCodeAttribute <data><AttributeFilter ClassMask="System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute" IsEnabled="True" /><AttributeFilter ClassMask="System.CodeDom.Compiler.GeneratedCodeAttribute" IsEnabled="True" /></data> + MergeVsActionsIntoResharperMenu True True True diff --git a/Common.targets b/Common.targets new file mode 100644 index 00000000..2992475b --- /dev/null +++ b/Common.targets @@ -0,0 +1,7 @@ + + + + + + + diff --git a/schemas/buildvana.schema.json b/schemas/buildvana.schema.json index b879f663..55becb7b 100644 --- a/schemas/buildvana.schema.json +++ b/schemas/buildvana.schema.json @@ -95,7 +95,10 @@ "description": "Environment variables forwarded to \u0060dotnet\u0060, keyed by variable name.", "type": "object", "additionalProperties": { - "type": "string" + "type": [ + "string", + "null" + ] } } }, diff --git a/src/Buildvana.Core.Abstractions/BuildFailedException.cs b/src/Buildvana.Core.Abstractions/BuildFailedException.cs index d307967a..5bbbe523 100644 --- a/src/Buildvana.Core.Abstractions/BuildFailedException.cs +++ b/src/Buildvana.Core.Abstractions/BuildFailedException.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Runtime.CompilerServices; namespace Buildvana.Core; diff --git a/src/Buildvana.Core.Abstractions/Buildvana.Core.Abstractions.csproj b/src/Buildvana.Core.Abstractions/Buildvana.Core.Abstractions.csproj index d49630b7..4cbb56d1 100644 --- a/src/Buildvana.Core.Abstractions/Buildvana.Core.Abstractions.csproj +++ b/src/Buildvana.Core.Abstractions/Buildvana.Core.Abstractions.csproj @@ -8,8 +8,4 @@ false - - - - diff --git a/src/Buildvana.Core.Abstractions/Process/IProcessRunner.cs b/src/Buildvana.Core.Abstractions/Process/IProcessRunner.cs index 9f70ed4e..fefc15f2 100644 --- a/src/Buildvana.Core.Abstractions/Process/IProcessRunner.cs +++ b/src/Buildvana.Core.Abstractions/Process/IProcessRunner.cs @@ -18,8 +18,13 @@ public interface IProcessRunner /// /// The path to (or name of) the executable to run. /// The arguments to pass to . - /// The working directory in which to run the process, or to inherit the current process's working directory. - /// If (the default), a is thrown when the process exits with a non-zero exit code; if , the result is returned regardless of exit code. + /// Environment variables to apply on top of the inherited environment: each entry adds or + /// overrides a variable, and a value removes that variable from the child process. Pass + /// to run with the current process's environment unchanged. + /// The working directory in which to run the process, or + /// to inherit the current process's working directory. + /// If (the default), a is thrown when + /// the process exits with a non-zero exit code; if , the result is returned regardless of exit code. /// An optional callback invoked once per line of standard output as it is produced. /// The full output text is captured into the returned regardless. /// An optional callback invoked once per line of standard error as it is produced. @@ -29,6 +34,7 @@ public interface IProcessRunner Task RunAsync( string executable, IEnumerable args, + IReadOnlyDictionary? environment = null, string? workingDirectory = null, bool throwOnNonZero = true, Action? onStdout = null, diff --git a/src/Buildvana.Core.Configuration/Buildvana.Core.Configuration.csproj b/src/Buildvana.Core.Configuration/Buildvana.Core.Configuration.csproj index 0771c421..cb4d8da7 100644 --- a/src/Buildvana.Core.Configuration/Buildvana.Core.Configuration.csproj +++ b/src/Buildvana.Core.Configuration/Buildvana.Core.Configuration.csproj @@ -13,7 +13,6 @@ - diff --git a/src/Buildvana.Core.Configuration/DotNetInvocationConfig.cs b/src/Buildvana.Core.Configuration/DotNetInvocationConfig.cs index ea314293..9f009538 100644 --- a/src/Buildvana.Core.Configuration/DotNetInvocationConfig.cs +++ b/src/Buildvana.Core.Configuration/DotNetInvocationConfig.cs @@ -18,5 +18,5 @@ public sealed record DotNetInvocationConfig /// Gets environment variables forwarded to dotnet, keyed by variable name. /// [Description("Environment variables forwarded to `dotnet`, keyed by variable name.")] - public IReadOnlyDictionary? Env { get; init; } + public IReadOnlyDictionary? Env { get; init; } } diff --git a/src/Buildvana.Core.HomeDirectory/HomeDirectoryDiscovery.cs b/src/Buildvana.Core.HomeDirectory/HomeDirectoryDiscovery.cs index d2bb682b..44303aef 100644 --- a/src/Buildvana.Core.HomeDirectory/HomeDirectoryDiscovery.cs +++ b/src/Buildvana.Core.HomeDirectory/HomeDirectoryDiscovery.cs @@ -35,7 +35,7 @@ public static bool TryDiscover(string startDirectory, [MaybeNullWhen(false)] out { Guard.IsNotNullOrEmpty(startDirectory); - string? current = Path.GetFullPath(startDirectory); + var current = Path.GetFullPath(startDirectory); while (current is not null) { if (DirectoryContainsMarker(current)) diff --git a/src/Buildvana.Core.JsonSchema/Buildvana.Core.JsonSchema.csproj b/src/Buildvana.Core.JsonSchema/Buildvana.Core.JsonSchema.csproj index 55565ce6..2ef1dd09 100644 --- a/src/Buildvana.Core.JsonSchema/Buildvana.Core.JsonSchema.csproj +++ b/src/Buildvana.Core.JsonSchema/Buildvana.Core.JsonSchema.csproj @@ -2,7 +2,7 @@ Buildvana JSON schema - Generic JSON schema generation and validation, independent of any specific model. Reports validation failures via JsonSchemaValidationException. + Generic JSON schema generation and validation, independent of any specific model. $(StandardTfm) diff --git a/src/Buildvana.Core.JsonSchema/JsonNullableAttribute.cs b/src/Buildvana.Core.JsonSchema/JsonNullableAttribute.cs index ca79375e..653c6c6c 100644 --- a/src/Buildvana.Core.JsonSchema/JsonNullableAttribute.cs +++ b/src/Buildvana.Core.JsonSchema/JsonNullableAttribute.cs @@ -14,6 +14,4 @@ namespace Buildvana.Core.JsonSchema; /// "unset", and an explicit null is disallowed by the generated schema. /// [AttributeUsage(AttributeTargets.Property)] -public sealed class JsonNullableAttribute : Attribute -{ -} +public sealed class JsonNullableAttribute : Attribute; diff --git a/src/Buildvana.Core.JsonSchema/JsonSchemaGenerator.cs b/src/Buildvana.Core.JsonSchema/JsonSchemaGenerator.cs index f75a36e1..afaac43b 100644 --- a/src/Buildvana.Core.JsonSchema/JsonSchemaGenerator.cs +++ b/src/Buildvana.Core.JsonSchema/JsonSchemaGenerator.cs @@ -20,6 +20,13 @@ namespace Buildvana.Core.JsonSchema; /// /// The same should drive both generation and deserialization, so the /// schema always describes exactly what the deserializer accepts. +/// marks every reference-type dictionary value and collection element +/// nullable regardless of how the model annotates it, so the generator reconciles that against the declared +/// nullability read from the owning property or field via . This requires +/// a member to read the annotations from: when the type being described is itself a dictionary or +/// collection (so its values or elements have no owning member), their declared nullability cannot be +/// recovered and the nullability emitted by the exporter is kept as-is. Wrap such a type in a containing +/// object property to control the nullability of its values or elements. /// public static class JsonSchemaGenerator { @@ -44,7 +51,11 @@ public static JsonNode Generate(Type type, JsonSerializerOptions options) ArgumentNullException.ThrowIfNull(type); ArgumentNullException.ThrowIfNull(options); - var exporterOptions = new JsonSchemaExporterOptions { TransformSchemaNode = TransformSchemaNode }; + var nullabilityContext = new NullabilityInfoContext(); + var exporterOptions = new JsonSchemaExporterOptions + { + TransformSchemaNode = (context, schema) => TransformSchemaNode(context, schema, nullabilityContext), + }; var schema = options.GetJsonSchemaAsNode(type, exporterOptions); // Declare the dialect and (optionally) a title so editors recognize and label the document. @@ -60,7 +71,10 @@ public static JsonNode Generate(Type type, JsonSerializerOptions options) return schema; } - private static JsonNode TransformSchemaNode(JsonSchemaExporterContext context, JsonNode schema) + private static JsonNode TransformSchemaNode( + JsonSchemaExporterContext context, + JsonNode schema, + NullabilityInfoContext nullabilityContext) { var attributeProvider = context.PropertyInfo is not null ? context.PropertyInfo.AttributeProvider @@ -68,17 +82,32 @@ private static JsonNode TransformSchemaNode(JsonSchemaExporterContext context, J schema = ApplyDescription(attributeProvider, schema); - // Strip "null" wherever the exporter emits it, except where a property opts in with [JsonNullable]: - // a nullable property otherwise means "unset" (an absent key), which needs no explicit null. + // Strip the "null" the exporter adds to a property's own type: a nullable property means "optional" + // (an absent key already expresses "unset"), so an explicit null is redundant unless the property + // opts in with [JsonNullable]. Value and element nodes skip this — their nullability is reconciled + // by the owning property below, because the exporter marks every reference-type value or element + // nullable regardless of how the model actually declares it. + var isValueOrElement = context.PropertyInfo is null && !context.Path.IsEmpty; var keepNull = attributeProvider?.IsDefined(typeof(JsonNullableAttribute), inherit: true) ?? false; - if (!keepNull && schema is JsonObject nullableSchema) + if (!isValueOrElement && !keepNull && schema is JsonObject ownSchema) { - RemoveNullFromType(nullableSchema); - RemoveNullFromEnum(nullableSchema); + RemoveNullFromType(ownSchema); + RemoveNullFromEnum(ownSchema); } - // Close a dictionary to a fixed set of keys when the property carries [JsonAllowedKeys]. The exporter - // runs this transform bottom-up, so the value schema cloned below is already null-stripped. + // Reconcile the nullability the exporter put on this property's values and elements with what the + // model actually declares (string vs string?), recursing through nested generics. This runs before + // ConstrainKeys so the keys it clones inherit the corrected value schema. + if (context.PropertyInfo?.AttributeProvider is MemberInfo member && schema is JsonObject propertySchema) + { + var nullability = CreateNullabilityInfo(nullabilityContext, member); + if (nullability is not null) + { + ReconcileValueNullability(propertySchema, nullability); + } + } + + // Close a dictionary to a fixed set of keys when the property carries [JsonAllowedKeys]. if (TryGetAllowedKeys(attributeProvider, out var keys) && schema is JsonObject dictionarySchema) { ConstrainKeys(dictionarySchema, keys); @@ -87,6 +116,65 @@ private static JsonNode TransformSchemaNode(JsonSchemaExporterContext context, J return schema; } + private static NullabilityInfo? CreateNullabilityInfo(NullabilityInfoContext context, MemberInfo member) + => member switch + { + PropertyInfo property => context.Create(property), + FieldInfo field => context.Create(field), + _ => null, + }; + + // Walks a property schema's value ("additionalProperties") and element ("items") subschemas alongside + // the matching nullability metadata, keeping "null" only where the model declares the value or element + // nullable. Recurses so nested generics (a dictionary of lists, say) are handled at every level. + private static void ReconcileValueNullability(JsonObject schema, NullabilityInfo nullability) + { + if (schema["additionalProperties"] is JsonObject valueSchema) + { + ApplyDeclaredNullability(valueSchema, GetValueNullability(nullability)); + } + + if (schema["items"] is JsonObject itemSchema) + { + ApplyDeclaredNullability(itemSchema, GetElementNullability(nullability)); + } + } + + private static void ApplyDeclaredNullability(JsonObject schema, NullabilityInfo? nullability) + { + if (nullability is null) + { + return; + } + + if (nullability.ReadState != NullabilityState.Nullable) + { + RemoveNullFromType(schema); + RemoveNullFromEnum(schema); + } + + ReconcileValueNullability(schema, nullability); + } + + // The value type of a dictionary is its last generic argument (IReadOnlyDictionary). + private static NullabilityInfo? GetValueNullability(NullabilityInfo nullability) + { + var args = nullability.GenericTypeArguments; + return args.Length > 0 ? args[^1] : null; + } + + // The element type is the array element, or the single generic argument of a collection. + private static NullabilityInfo? GetElementNullability(NullabilityInfo nullability) + { + if (nullability.ElementType is { } elementType) + { + return elementType; + } + + var args = nullability.GenericTypeArguments; + return args.Length == 1 ? args[0] : null; + } + // Surfaces a [Description] (on the property, or on the type) as a schema "description" keyword. // Adapted from the System.Text.Json schema-exporter documentation sample. private static JsonNode ApplyDescription(ICustomAttributeProvider? attributeProvider, JsonNode schema) diff --git a/src/Buildvana.Core.JsonSchema/JsonSchemaValidationException.cs b/src/Buildvana.Core.JsonSchema/JsonSchemaValidationException.cs deleted file mode 100644 index beb7f965..00000000 --- a/src/Buildvana.Core.JsonSchema/JsonSchemaValidationException.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (C) Tenacom and Contributors. Licensed under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Buildvana.Core.JsonSchema; - -/// -/// The exception thrown when a JSON value fails validation against a schema. -/// -public sealed class JsonSchemaValidationException : Exception -{ - /// - /// Initializes a new instance of the class with no errors. - /// - public JsonSchemaValidationException() - : this([]) - { - } - - /// - /// Initializes a new instance of the class with the specified message. - /// - /// A message describing the validation failure. - public JsonSchemaValidationException(string message) - : base(message) - { - Errors = []; - } - - /// - /// Initializes a new instance of the class with the specified - /// message and inner exception. - /// - /// A message describing the validation failure. - /// The exception that caused the current exception. - public JsonSchemaValidationException(string message, Exception innerException) - : base(message, innerException) - { - Errors = []; - } - - /// - /// Initializes a new instance of the class with the specified errors. - /// - /// The validation errors that caused the failure. - public JsonSchemaValidationException(IReadOnlyList errors) - : base(FormatMessage(errors)) - { - Errors = errors; - } - - /// - /// Gets the validation errors that caused the failure. - /// - public IReadOnlyList Errors { get; } - - private static string FormatMessage(IReadOnlyList errors) - { - ArgumentNullException.ThrowIfNull(errors); - return errors.Count switch - { - 0 => "JSON schema validation failed.", - 1 => $"JSON schema validation failed: {errors[0]}", - _ => "JSON schema validation failed:" + Environment.NewLine - + string.Join(Environment.NewLine, errors.Select(static error => $" - {error}")), - }; - } -} diff --git a/src/Buildvana.Core.JsonSchema/JsonSchemaValidator.cs b/src/Buildvana.Core.JsonSchema/JsonSchemaValidator.cs index acd6607f..cfa1b4e2 100644 --- a/src/Buildvana.Core.JsonSchema/JsonSchemaValidator.cs +++ b/src/Buildvana.Core.JsonSchema/JsonSchemaValidator.cs @@ -96,21 +96,6 @@ public static IReadOnlyList Validate( return located; } - /// - /// Validates against and throws if it is invalid. - /// - /// The JSON value to validate. represents a JSON null. - /// The schema to validate against. - /// is invalid. - public static void ValidateAndThrow(JsonNode? instance, JsonNode schema) - { - var errors = Validate(instance, schema); - if (errors.Count > 0) - { - throw new JsonSchemaValidationException(errors); - } - } - private static void ValidateNode( JsonNode? instance, JsonNode schemaNode, diff --git a/src/Buildvana.Core.Process/ProcessRunner.cs b/src/Buildvana.Core.Process/ProcessRunner.cs index 5ad080af..4d14fd2f 100644 --- a/src/Buildvana.Core.Process/ProcessRunner.cs +++ b/src/Buildvana.Core.Process/ProcessRunner.cs @@ -25,6 +25,7 @@ public sealed class ProcessRunner : IProcessRunner public async Task RunAsync( string executable, IEnumerable args, + IReadOnlyDictionary? environment = null, string? workingDirectory = null, bool throwOnNonZero = true, Action? onStdout = null, @@ -69,6 +70,11 @@ public async Task RunAsync( .WithStandardErrorPipe(stderrPipe) .WithValidation(CommandResultValidation.None); + if (environment is not null) + { + command = command.WithEnvironmentVariables(environment); + } + if (workingDirectory is not null) { command = command.WithWorkingDirectory(workingDirectory); diff --git a/src/Buildvana.Sdk.SourceGenerators/Internal/AdditionalAssemblyInfoValues.cs b/src/Buildvana.Sdk.SourceGenerators/Internal/AdditionalAssemblyInfoValues.cs index f034c97f..0c4c5573 100644 --- a/src/Buildvana.Sdk.SourceGenerators/Internal/AdditionalAssemblyInfoValues.cs +++ b/src/Buildvana.Sdk.SourceGenerators/Internal/AdditionalAssemblyInfoValues.cs @@ -3,4 +3,5 @@ namespace Buildvana.Sdk.SourceGenerators.Internal; +// ReSharper disable once InconsistentNaming - CLSCompliant is the actual name of the attribute, and it's more readable to keep it as-is in this context. internal readonly record struct AdditionalAssemblyInfoValues(bool? CLSCompliant, bool? ComVisible); diff --git a/src/Buildvana.Sdk.Tasks/.editorconfig b/src/Buildvana.Sdk.Tasks/.editorconfig new file mode 100644 index 00000000..e55cc8cb --- /dev/null +++ b/src/Buildvana.Sdk.Tasks/.editorconfig @@ -0,0 +1,8 @@ +# Project-specific .editorconfig file + +root = false + +[*.cs] + +# Task properties are set by the build engine, not in our code. "Unused" getters are not a concern. +resharper_auto_property_can_be_made_get_only_global_highlighting = none diff --git a/src/Buildvana.Sdk.Tasks/Buildvana.Sdk.Tasks.csproj b/src/Buildvana.Sdk.Tasks/Buildvana.Sdk.Tasks.csproj index a539a264..7e1a9e88 100644 --- a/src/Buildvana.Sdk.Tasks/Buildvana.Sdk.Tasks.csproj +++ b/src/Buildvana.Sdk.Tasks/Buildvana.Sdk.Tasks.csproj @@ -19,7 +19,6 @@ - diff --git a/src/Buildvana.Sdk.Tasks/Internal/JetBrainsAnnotationsExporter.cs b/src/Buildvana.Sdk.Tasks/Internal/JetBrainsAnnotationsExporter.cs index a05e0523..62830aea 100644 --- a/src/Buildvana.Sdk.Tasks/Internal/JetBrainsAnnotationsExporter.cs +++ b/src/Buildvana.Sdk.Tasks/Internal/JetBrainsAnnotationsExporter.cs @@ -124,7 +124,7 @@ private static IEnumerable GetTypeAndNested(INamedTypeSymbol t private static bool IsExternallyVisible(INamedTypeSymbol type) { - for (INamedTypeSymbol? current = type; current is not null; current = current.ContainingType) + for (var current = type; current is not null; current = current.ContainingType) { if (!IsExternallyVisible(current.DeclaredAccessibility)) { diff --git a/src/Buildvana.Sdk.Tasks/TaskLoggingHelperLogger.cs b/src/Buildvana.Sdk.Tasks/TaskLoggingHelperLogger.cs index 0999fe72..20174f40 100644 --- a/src/Buildvana.Sdk.Tasks/TaskLoggingHelperLogger.cs +++ b/src/Buildvana.Sdk.Tasks/TaskLoggingHelperLogger.cs @@ -34,8 +34,7 @@ public IDisposable BeginScope(TState state) public bool IsEnabled(LogLevel logLevel) => logLevel switch { - LogLevel.Trace => LogsMessagesOfImportance(MessageImportance.Low), - LogLevel.Debug => LogsMessagesOfImportance(MessageImportance.Low), + LogLevel.Trace or LogLevel.Debug => LogsMessagesOfImportance(MessageImportance.Low), LogLevel.Information => LogsMessagesOfImportance(MessageImportance.Normal), LogLevel.Warning => true, LogLevel.Error => true, diff --git a/src/Buildvana.Sdk.Tasks/Undefined.cs b/src/Buildvana.Sdk.Tasks/Undefined.cs index a9fe3c78..395439f0 100644 --- a/src/Buildvana.Sdk.Tasks/Undefined.cs +++ b/src/Buildvana.Sdk.Tasks/Undefined.cs @@ -9,12 +9,14 @@ namespace Buildvana.Sdk; { public static Undefined Value => default; + // ReSharper disable UnusedParameter.Global - Undefined is a unit type; all values are equal. public static bool operator ==(Undefined first, Undefined second) => true; public static bool operator !=(Undefined first, Undefined second) => false; public bool Equals(Undefined other) => true; + // ReSharper restore UnusedParameter.Global public override bool Equals(object? obj) => obj is Undefined; public override int GetHashCode() => 0; diff --git a/src/Buildvana.Tool/Buildvana.Tool.csproj b/src/Buildvana.Tool/Buildvana.Tool.csproj index 33cf7a95..459d8662 100644 --- a/src/Buildvana.Tool/Buildvana.Tool.csproj +++ b/src/Buildvana.Tool/Buildvana.Tool.csproj @@ -34,7 +34,6 @@ - diff --git a/src/Buildvana.Tool/Services/DotNetService.InvocationKind.cs b/src/Buildvana.Tool/Services/DotNetService.InvocationKind.cs index b72f1068..86018278 100644 --- a/src/Buildvana.Tool/Services/DotNetService.InvocationKind.cs +++ b/src/Buildvana.Tool/Services/DotNetService.InvocationKind.cs @@ -14,6 +14,7 @@ private enum InvocationKind /// /// An informational invocation: the user is interested in the output, but `dotnet` does not accept the `--verbosity` argument. + /// `dotnet` output is streamed at `Normal` verbosity. /// Informational, diff --git a/src/Buildvana.Tool/Services/DotNetService.cs b/src/Buildvana.Tool/Services/DotNetService.cs index 86e6d76b..239e939c 100644 --- a/src/Buildvana.Tool/Services/DotNetService.cs +++ b/src/Buildvana.Tool/Services/DotNetService.cs @@ -82,7 +82,7 @@ public Task RestoreSolutionAsync(SolutionContext solution, IReadOnlyList ContinuousIntegrationBuildArg(asMSBuildPassthrough: true), ]; - return RunDotNetAsync(args, InvocationKind.Normal, cancellationToken: cancellationToken); + return RunDotNetAsync(args, cancellationToken: cancellationToken); } /// @@ -110,7 +110,7 @@ public Task BuildSolutionAsync(SolutionContext solution, string configuration, I ContinuousIntegrationBuildArg(asMSBuildPassthrough: true), ]; - return RunDotNetAsync(args, InvocationKind.Normal, cancellationToken: cancellationToken); + return RunDotNetAsync(args, cancellationToken: cancellationToken); } /// @@ -139,7 +139,7 @@ public async Task TestSolutionAsync(SolutionContext solution, string configurati // bv-internal MSBuild evaluation: do not forward the user's arguments here, as they may be // test-application options that `dotnet msbuild` would reject. string[] probeArgs = ["msbuild", projectPath, "-nologo", "-getProperty:IsTestingPlatformApplication"]; - var probe = await RunDotNetAsync(probeArgs, InvocationKind.Internal, cancellationToken: cancellationToken).ConfigureAwait(false); + var probe = await RunDotNetAsync(probeArgs, null, InvocationKind.Internal, cancellationToken: cancellationToken).ConfigureAwait(false); if (string.Equals(probe.StandardOutput.Trim(), "true", StringComparison.OrdinalIgnoreCase)) { @@ -174,7 +174,7 @@ public async Task TestSolutionAsync(SolutionContext solution, string configurati ContinuousIntegrationBuildArg(asMSBuildPassthrough: false), ]; - await RunDotNetAsync(args, InvocationKind.Normal, cancellationToken: cancellationToken).ConfigureAwait(false); + await RunDotNetAsync(args, cancellationToken: cancellationToken).ConfigureAwait(false); } /// @@ -204,7 +204,7 @@ public Task PackSolutionAsync(SolutionContext solution, string configuration, IR ContinuousIntegrationBuildArg(asMSBuildPassthrough: true), ]; - return RunDotNetAsync(args, InvocationKind.Normal, cancellationToken: cancellationToken); + return RunDotNetAsync(args, cancellationToken: cancellationToken); } /// @@ -232,6 +232,9 @@ public async Task NuGetPushAllAsync(string artifactsPath, CancellationToken canc { _reporter.Detail($"Pushing {path} to {target.Source}..."); string[] args = [ + + // `dotnet nuget` has no verbosity option; use the global diagnostics flag when diagnostic output is enabled. + .. _reporter.IsVerbosityAtLeast(Verbosity.Diagnostic) ? ["-d"] : Array.Empty(), "nuget", "push", path, @@ -241,7 +244,7 @@ public async Task NuGetPushAllAsync(string artifactsPath, CancellationToken canc target.ApiKey, "--skip-duplicate", ]; - await _processRunner.RunAsync(DotNetMuxer, args, cancellationToken: cancellationToken).ConfigureAwait(false); + await RunDotNetAsync(args, invocationKind: InvocationKind.Informational, cancellationToken: cancellationToken).ConfigureAwait(false); } _reporter.Info($"Pushed {packages.Length} packages to {target.Source}."); @@ -268,21 +271,23 @@ private string ContinuousIntegrationBuildArg(bool asMSBuildPassthrough) /// A representing the ongoing operation, with a result describing child process outcome. private Task RunDotNetAsync( IEnumerable args, - InvocationKind invocationKind, + IReadOnlyDictionary? environment = null, + InvocationKind invocationKind = InvocationKind.Normal, CancellationToken cancellationToken = default) { - var (appendVerbosity, streamOutput) = invocationKind switch { - InvocationKind.Normal => (AppendVerbosity: true, StreamOutput: true), - InvocationKind.Informational => (AppendVerbosity: false, StreamOutput: true), - InvocationKind.Internal => (AppendVerbosity: false, StreamOutput: false), + var (appendVerbosity, streamOutput, streamVerbosity) = invocationKind switch { + InvocationKind.Normal => (AppendVerbosity: true, StreamOutput: true, StreamVerbosity: null as Verbosity?), + InvocationKind.Informational => (AppendVerbosity: false, StreamOutput: true, StreamVerbosity: Verbosity.Normal), + InvocationKind.Internal => (AppendVerbosity: false, StreamOutput: false, StreamVerbosity: null), _ => throw new UnreachableException(), }; return _processRunner.RunAsync( DotNetMuxer, appendVerbosity ? args.Append($"--verbosity={_reporter.Verbosity}") : args, - onStdout: streamOutput ? (x) => _reporter.ChildOutput(x, null) : null, - onStderr: streamOutput ? (x) => _reporter.ChildError(x, null) : null, + environment: environment, + onStdout: streamOutput ? (x) => _reporter.ChildOutput(x, streamVerbosity) : null, + onStderr: streamOutput ? (x) => _reporter.ChildError(x, streamVerbosity) : null, cancellationToken: cancellationToken); } } diff --git a/src/Buildvana.Tool/Services/ServerAdapters/Internal/GitLab/GitLabServerAdapter.cs b/src/Buildvana.Tool/Services/ServerAdapters/Internal/GitLab/GitLabServerAdapter.cs index 66877c6f..8c249280 100644 --- a/src/Buildvana.Tool/Services/ServerAdapters/Internal/GitLab/GitLabServerAdapter.cs +++ b/src/Buildvana.Tool/Services/ServerAdapters/Internal/GitLab/GitLabServerAdapter.cs @@ -14,7 +14,7 @@ namespace Buildvana.Tool.Services.ServerAdapters.Internal.GitLab; /// internal sealed class GitLabServerAdapter : ServerAdapter { - internal GitLabServerAdapter() + private GitLabServerAdapter() { CIBotIdentity = new("GitLab CI", $"gitlab-ci@noreply.{Environment.GetEnvironmentVariable("CI_SERVER_HOST")}"); } diff --git a/src/Buildvana.Tool/Services/ServerAdapters/ServerAdapter.cs b/src/Buildvana.Tool/Services/ServerAdapters/ServerAdapter.cs index 3375f31e..463a1973 100644 --- a/src/Buildvana.Tool/Services/ServerAdapters/ServerAdapter.cs +++ b/src/Buildvana.Tool/Services/ServerAdapters/ServerAdapter.cs @@ -27,6 +27,7 @@ private protected ServerAdapter() /// /// Gets the name of the remote repository's host. /// + // ReSharper disable once UnusedMemberInSuper.Global - We may need this property in the future public abstract string HostName { get; } /// @@ -101,6 +102,7 @@ public static ServerAdapter Create(IServiceProvider services) /// The path to the file. /// The SHA or reference to which the file belongs. /// + // ReSharper disable once UnusedMemberInSuper.Global - We may need this method in the future public abstract Uri GetFileUrl(string path, string commitish); /// diff --git a/tests/.editorconfig b/tests/.editorconfig new file mode 100644 index 00000000..31adefbb --- /dev/null +++ b/tests/.editorconfig @@ -0,0 +1,8 @@ +# Test-specific .editorconfig file + +root = false + +[*.cs] + +# Test methods can have compound or expression bodies, as appropriate for the test. +resharper_arrange_method_or_operator_body_highlighting = none diff --git a/tests/Buildvana.Core.Configuration.Tests/Buildvana.Core.Configuration.Tests.csproj b/tests/Buildvana.Core.Configuration.Tests/Buildvana.Core.Configuration.Tests.csproj index 603da20a..35eff46e 100644 --- a/tests/Buildvana.Core.Configuration.Tests/Buildvana.Core.Configuration.Tests.csproj +++ b/tests/Buildvana.Core.Configuration.Tests/Buildvana.Core.Configuration.Tests.csproj @@ -3,8 +3,6 @@ Exe $(StandardTfm) - true - true false true diff --git a/tests/Buildvana.Core.JsonSchema.Tests/Buildvana.Core.JsonSchema.Tests.csproj b/tests/Buildvana.Core.JsonSchema.Tests/Buildvana.Core.JsonSchema.Tests.csproj index 41b0f64a..5903bd00 100644 --- a/tests/Buildvana.Core.JsonSchema.Tests/Buildvana.Core.JsonSchema.Tests.csproj +++ b/tests/Buildvana.Core.JsonSchema.Tests/Buildvana.Core.JsonSchema.Tests.csproj @@ -3,8 +3,6 @@ Exe $(StandardTfm) - true - true false true diff --git a/tests/Buildvana.Core.JsonSchema.Tests/GeneratorSample.cs b/tests/Buildvana.Core.JsonSchema.Tests/GeneratorSample.cs index 279e899a..d6aef857 100644 --- a/tests/Buildvana.Core.JsonSchema.Tests/GeneratorSample.cs +++ b/tests/Buildvana.Core.JsonSchema.Tests/GeneratorSample.cs @@ -22,4 +22,16 @@ internal sealed record GeneratorSample [JsonAllowedKeys("alpha, beta")] public IReadOnlyDictionary? Map { get; init; } + + // Nullable dictionary value: the schema should keep "null" on the value type without any opt-in. + public IReadOnlyDictionary? Env { get; init; } + + // Non-nullable dictionary value: the schema should strip the "null" the exporter adds. + public IReadOnlyDictionary? Vars { get; init; } + + // Nullable array element: the schema should keep "null" on the item type without any opt-in. + public IReadOnlyList? Items { get; init; } + + // Non-nullable array element: the schema should strip the "null" the exporter adds. + public IReadOnlyList? Tags { get; init; } } diff --git a/tests/Buildvana.Core.JsonSchema.Tests/JsonSchemaGeneratorTests.cs b/tests/Buildvana.Core.JsonSchema.Tests/JsonSchemaGeneratorTests.cs index 28f0d7c0..df7d95a2 100644 --- a/tests/Buildvana.Core.JsonSchema.Tests/JsonSchemaGeneratorTests.cs +++ b/tests/Buildvana.Core.JsonSchema.Tests/JsonSchemaGeneratorTests.cs @@ -56,5 +56,37 @@ public async Task Generate_ConstrainsDictionaryToAllowedKeys() await Assert.That((map["properties"] as JsonObject)!.Count).IsEqualTo(2); } + [Test] + public async Task Generate_KeepsNullOnNullableDictionaryValue() + { + var type = Generate()["properties"]!["env"]!["additionalProperties"]!["type"]; + await Assert.That(type is JsonArray).IsTrue(); + await Assert.That(((JsonArray)type!).Count).IsEqualTo(2); + } + + [Test] + public async Task Generate_StripsNullFromNonNullableDictionaryValue() + { + var type = Generate()["properties"]!["vars"]!["additionalProperties"]!["type"]; + await Assert.That(type!.GetValueKind()).IsEqualTo(JsonValueKind.String); + await Assert.That(type.GetValue()).IsEqualTo("string"); + } + + [Test] + public async Task Generate_KeepsNullOnNullableArrayElement() + { + var type = Generate()["properties"]!["items"]!["items"]!["type"]; + await Assert.That(type is JsonArray).IsTrue(); + await Assert.That(((JsonArray)type!).Count).IsEqualTo(2); + } + + [Test] + public async Task Generate_StripsNullFromNonNullableArrayElement() + { + var type = Generate()["properties"]!["tags"]!["items"]!["type"]; + await Assert.That(type!.GetValueKind()).IsEqualTo(JsonValueKind.String); + await Assert.That(type.GetValue()).IsEqualTo("string"); + } + private static JsonNode Generate() => JsonSchemaGenerator.Generate(Options); } diff --git a/tests/Buildvana.Core.JsonSchema.Tests/JsonSchemaValidatorTests.cs b/tests/Buildvana.Core.JsonSchema.Tests/JsonSchemaValidatorTests.cs index 8514645b..ed45dcbf 100644 --- a/tests/Buildvana.Core.JsonSchema.Tests/JsonSchemaValidatorTests.cs +++ b/tests/Buildvana.Core.JsonSchema.Tests/JsonSchemaValidatorTests.cs @@ -1,7 +1,6 @@ // Copyright (C) Tenacom and Contributors. Licensed under the MIT license. // See the LICENSE file in the project root for full license information. -using System.Text; using System.Text.Json.Nodes; using Buildvana.Core.JsonSchema; @@ -107,7 +106,7 @@ public async Task Validate_UnresolvableRef_Throws() public async Task Validate_WithBytes_FillsLineAndColumn() { var schema = Schema("""{"type":"object","properties":{"name":{"type":"string"}}}"""); - var bytes = Encoding.UTF8.GetBytes("{\n \"name\": 42\n}"); + var bytes = "{\n \"name\": 42\n}"u8; var errors = JsonSchemaValidator.Validate(JsonNode.Parse(bytes), schema, bytes); await Assert.That(errors.Count).IsEqualTo(1); await Assert.That(errors[0].Line).IsEqualTo(2); diff --git a/tests/Buildvana.Tool.Tests/Buildvana.Tool.Tests.csproj b/tests/Buildvana.Tool.Tests/Buildvana.Tool.Tests.csproj index 8d0238bc..58cca09b 100644 --- a/tests/Buildvana.Tool.Tests/Buildvana.Tool.Tests.csproj +++ b/tests/Buildvana.Tool.Tests/Buildvana.Tool.Tests.csproj @@ -3,8 +3,6 @@ Exe $(StandardTfm) - true - true false true