Skip to content

Releases: TNG/ArchUnitNET

0.13.5

Choose a tag to compare

@alexanderlinne alexanderlinne released this 26 Oct 18:07
f439e0d

Most of this release fixes cases where ArchUnitNET missed dependencies, crashed while loading or evaluating, or drew a wrong diagram. Dependencies inside async methods are now found in Release builds and in async lambdas, so rules that only passed because those dependencies were missing may start failing. Please read Upgrading before you update. Also in this release: ResideInNamespaceOrBelow and NotBeNestedIn, and much better PlantUML export for slices.

Highlights

  • Dependencies in async code are no longer lost. In optimized builds, every dependency inside an async method body used to be missing, and so were the dependencies inside async lambdas. Negative rules such as NotDependOnAny could therefore pass without checking anything.
  • Combined rules are now consistent. a.And(b) and b.And(a) now give the same result, and RequirePositiveResults is respected on both sides.
  • Slice diagrams are correct for more namespace layouts. Packages with the same name under different parents are no longer merged. Slice names that aren't valid PlantUML ids (like nested or generic type names) no longer produce broken diagrams, and C4 style works for slices without a namespace.

Added

  • ResideInNamespaceOrBelow and its negated forms. These match a namespace and all of its sub-namespaces, so a rule no longer needs to list every sub-namespace or use a regular expression like ^Foo\.Bar(\.|$). "Foo.Bar" matches Foo.Bar and Foo.Bar.Baz, but not Foo.BarBaz, and the comparison ignores case like ResideInNamespace does. Available as ResideInNamespaceOrBelow / NotResideInNamespaceOrBelow on conditions and ResideInNamespaceOrBelow / DoNotResideInNamespaceOrBelow on predicates. #511 (@StefanGreve)

    Types().That().ResideInNamespaceOrBelow("MyProject.Model")
        .Should().NotBePublic()
  • NotBeNestedIn / AreNotNestedIn. These are the negated forms of BeNestedIn / AreNestedIn, with the same overloads. #487 (@alexanderlinne)

Fixed

Loading and dependency analysis

  • Async methods in Release builds. In optimized builds the compiler creates async state machines as structs, which the loader didn't recognize. It then analyzed only the small method that starts the state machine and lost every call, new and field access inside the method body. The loader now reads the state machine from AsyncStateMachineAttribute / IteratorStateMachineAttribute. #500 (@iamAdarshh), fixes #498
  • Async lambdas. Dependencies inside async lambdas, e.g. Register(async () => C3.Bar()), are now added to the method that contains the lambda. #505 (@mkay-sh), fixes #230
  • Assemblies that can't be resolved. ArchLoader.Build() threw AssemblyResolutionException (for example for mscorlib in .NET Framework 4.8 SDK-style projects) when a referenced assembly couldn't be found. Types from such assemblies are now treated as unavailable, as intended. #502 (@mak638), fixes #497
  • Types without a namespace or assembly. Namespace and assembly predicates and conditions threw a NullReferenceException on Types(true) when the architecture contained function pointer types. Such types now simply don't reside in any namespace or assembly. #501 (@iamAdarshh), fixes #492

Rules

  • And / Or are commutative. A combined rule was built from the first rule's rule creator rather than from the rule itself. As a result, a rule whose predicate matched nothing counted as failing only when it was on the right-hand side of And / Or. HasNoViolations() and Evaluate() now also agree when a predicate matches nothing, and a combined rule now uses the inner rule's RequirePositiveResults instead of its own. #504 (@brandhuf)
  • AreStatic / AreNotStatic on members whose static state is unknown now behave the same as BeStatic / NotBeStatic. #485 (@alexanderlinne)
  • Interfaces().That()...As() / .Because() now return GivenInterfacesConjunctionWithDescription, like the other rule types. #486 (@alexanderlinne)

Slices and PlantUML export

  • Packages with the same name under different parents stay separate. PlantUML identifies a package by its name, so Orders.Domain and Billing.Domain were drawn as one Domain package, and an arrow to one of them could end in the other. Each package is now declared with its full path as its alias (package "Domain" as App.Billing.Domain) and keeps its own name as its label. #499 (@alexanderlinne)
  • Nested slices are written as one package tree. Before, every shared parent package was reopened once per slice. The .puml output is now shorter, indented by nesting level, and reads like a hand-written diagram. Hyperlinks on nested slices, which PlantUML used to reject, now work. #499 (@alexanderlinne)
  • Slice names that aren't valid PlantUML ids (for example Outer+Inner or List`1, which SlicedBy produces from type names) now get an id of their own. The name is still used as the label. #510 (@alexanderlinne)
  • C4 style works for slices without a namespace. Slices().Matching(...) with GenerationOptions.C4Style threw a NullReferenceException. Patterns that start with a capture group, such as MatchingWithPackages("(**).Service"), crashed the exporter in the same way. #495, #509 (@alexanderlinne)
  • OneToOneIfSameParentNamespace arrows now put component names in brackets like every other arrow type, so names that contain .. or * no longer break the diagram. #508 (@alexanderlinne)
  • Slice equality depends only on the slice's identifier. Two slices with the same identifier used to compare as different when their type lists were separate instances. This affected the deduplication of slices in diagrams and of violations in frozen rules. #507 (@alexanderlinne)

Upgrading

No changes to the fluent API are required. The following fixes can still change the results of existing tests:

  • Rules may find new violations. Dependencies inside async methods (in Release builds) and inside async lambdas are now part of the architecture. A rule that passed because they were missing will now report them. This most likely affects test suites that run in -c Release. Note that it is still recommended to run ArchUnitNET tests with -c Debug in order to have all features available.
  • Combined rules may fail where they passed before. If one side of an And / Or matches no objects, the combined rule now fails, unless that side uses WithoutRequiringPositiveResults(). Before, this depended on the order of the two rules.
  • The generated PlantUML text for slices has changed. It now uses package aliases, generated ids and indentation, and empty packages are drawn as package boxes. The rendered diagrams are otherwise unchanged. If you compare generated .puml files with saved copies, update the saved copies.
  • Removed HaveAnyAttributesWithArguments(object, params object[]) predicate overload. This leftover was missed when the other params object[] overloads were removed in 0.13.0. Pass a collection instead: HaveAnyAttributesWithArguments(new object[] { a, b }). #486
  • PropertyMemberPredicateDefinition was renamed to PropertyMemberPredicatesDefinition to match the other definition classes. This only matters if you use the class directly instead of the fluent API. #489

Testing and CI

  • Large expansion and cleanup of the fluent syntax and slice test suites. Snapshot output is now independent of loader order, and the assert helpers can no longer pass without checking anything. #484, #486, #488, #489, #490, #495 (@alexanderlinne)
  • NuGet packages are now published with NuGet trusted publishing instead of an API key. #483 (@alexanderlinne)
  • Development tools are pinned with mise, and hk runs formatting and lint checks (csharpier, actionlint, gitleaks, zizmor) through mise run check. Also includes security fixes in the GitHub Actions workflows and removal of the old Travis configuration. #482 (@alexanderlinne)
  • TUnit tests were updated to TUnit 0.90.45 and now run on Microsoft.Testing.Platform, in parallel with the VSTest-based test projects (mise run test). #491 (@mak638), #506 (@alexanderlinne)

New Contributors

Read more

0.13.4

Choose a tag to compare

@alexanderlinne alexanderlinne released this 19 Aug 15:01
1ab5943

Enhancement

Fixes

  • fix: Refine iterator and async method body scanning by @Optano-Dev in #469

Dependency Updates

  • chore(deps): update actions/checkout action to v7 by @renovate[bot] in #470
  • chore(deps): update codecov/codecov-action action to v7 by @renovate[bot] in #463
  • chore(deps): update dependency dotnet-sdk to v10.0.400 by @renovate[bot] in #436
  • chore(deps): update dependency jetbrains.annotations to v2026 by @renovate[bot] in #467
  • chore(deps): update all non-major dependencies by @renovate[bot] in #419

New Contributors

Full Changelog: 0.13.3...0.13.4

0.13.3

Choose a tag to compare

@alexanderlinne alexanderlinne released this 05 Mar 07:15
b25c4f9

What's Changed

Full Changelog: 0.13.2...0.13.3

0.13.2

Choose a tag to compare

@alexanderlinne alexanderlinne released this 23 Jan 18:21
6b80304

Enhancements

Fixes

  • DependOnAny and DoNotDependOnAny should check dependencies on referenced types by @alexanderlinne in #439

Documentation Fixes

New Contributors

Full Changelog: 0.13.1...0.13.2

0.13.1

Choose a tag to compare

@alexanderlinne alexanderlinne released this 15 Dec 16:17
c569fbb

Fixes

  • Record method call generic argument types as dependencies by @Itzalive in #437
  • Fix Assembly property of UnavailableType by @jpdurot in #431

New Contributors

Full Changelog: 0.13.0...0.13.1

0.13.0

Choose a tag to compare

@alexanderlinne alexanderlinne released this 05 Dec 15:12
cb83e98

Breaking Changes

Remove Obsolete Fluent Syntax Methods by @alexanderlinne in #412

As announced in version 0.12.0, fluent methods that take strings as an argument for matching the full name are now removed in favour of using fluent methods like .HaveName.

Refactor attribute with arguments fluent syntax methods by @alexanderlinne in #432

For HaveAttributeWithArguments and NotHaveAttributeWithArguments fluent methods, the overloads that take params object[] as arguments have been removed. This was previously ambiguous with the overload that takes an IEnumerable<object> as an argument.

Performance Enhancements

The following refactorings improve performance in our tests by ~15%:

CI Enhancements

Dependency Updates

  • Update dependency dotnet-sdk to v9.0.305 by @renovate[bot] in #407
  • Update all non-major dependencies by @renovate[bot] in #346
  • Update actions/setup-dotnet action to v5 by @renovate[bot] in #401
  • Update mstest monorepo to v3 (major) by @renovate[bot] in #310
  • chore(config): migrate renovate config by @renovate[bot] in #415
  • chore(deps): update dependency xunit.v3 to v3 by @renovate[bot] in #350
  • chore(deps): update dependency dotnet-sdk to v9.0.308 by @renovate[bot] in #425
  • chore(deps): update github/codeql-action action to v4 by @renovate[bot] in #421
  • chore(deps): update actions/checkout action to v6 by @renovate[bot] in #429
  • chore(deps): update dotnet version to v10 (major) by @renovate[bot] in #406

Full Changelog: 0.12.3...0.13.0

0.12.3

Choose a tag to compare

@alexanderlinne alexanderlinne released this 26 Sep 10:07
3a82c3e

Fixes

New Contributors

Full Changelog: 0.12.2...0.12.3

0.12.2

Choose a tag to compare

@alexanderlinne alexanderlinne released this 24 Sep 12:08
cfbfe15

Features

Enhancements

Dependency Updates

  • chore(deps): update actions/checkout action to v5 by @renovate[bot] in #391
  • chore(deps): update dependency dotnet-sdk to v9.0.304 by @renovate[bot] in #354
  • chore(deps): update dependency microsoft.net.test.sdk to v17 by @renovate[bot] in #349
  • chore(deps): update dependency verify.xunit to v30 by @renovate[bot] in #368
  • chore(deps): update dependency jetbrains.annotations to v2025 by @renovate[bot] in #386

New Contributors

Full Changelog: 0.12.1...0.12.2

0.12.1

Choose a tag to compare

@alexanderlinne alexanderlinne released this 14 Jul 09:36
41b7180

Fixes

  • ResideInNamespaceMatching and ResideInAssemblyMatching incorrectly forward call by @tnotheis in #379

New Contributors

Full Changelog: 0.12.0...0.12.1

0.12.0

Choose a tag to compare

@alexanderlinne alexanderlinne released this 11 Jul 13:15
cc39e12

Breaking Changes

Marking soon to be removed methods in the fluent api as obsolete by @brandhuf in #362

Until now, ArchUnitNET provided overloads of functions in the fluent syntax that took a string as an argument like Types().That().DependOnAny("ExampleClass") or Types().That().DependOnAny(".*ExampleClass", true). Here, however, it is unclear whether the string would match the Name, FullName or AssemblyQualifiedName. These functions have now been marked as obsolete and will be removed in version 0.13.0.

Besides HaveName, the fluent interface now also provides the functions HaveNameMatching, HaveFullName and HaveFullNameMatching. The above call can therefore be replaced with Types().That().DependOnAny(Types().That().HaveName("ExampleClass")) or Types().That().DependOnAny(Types().That().HaveFullNameMatching(".*ExampleClass")), giving a clear indication of what is matched and how it is matched.

Don't Set Assembly Name To It's Full Name by @alexanderlinne in #372

This is a bug where the Name of an assembly was always set to its FullName. This may be a breaking change for code that currently relies on this behaviour.

Fixes

Enhancements

Dependency Updates

  • chore(deps): update dependency csharpier to v1 by @renovate[bot] in #364

Full Changelog: 0.11.4...0.12.0