Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Arc.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<Project Path="Source\DotNET\Chronicle.Testing\Chronicle.Testing.csproj" />
<Project Path="Source\DotNET\Cratis.Testing\Cratis.Testing.csproj" />
<Project Path="Source\DotNET\Cratis\Cratis.csproj" />
<Project Path="Source\DotNET\Cratis.CodeAnalysis\Cratis.CodeAnalysis.csproj" />
<Project Path="Source\DotNET\Chronicle\Chronicle.csproj" />
<Project Path="Source\DotNET\Chronicle.Specs\Chronicle.Specs.csproj" />
<Project Path="Source\DotNET\Chronicle.CodeAnalysis\Chronicle.CodeAnalysis.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) Cratis. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Diagnostics;
using System.IO.Compression;

namespace Cratis.Arc.Core.Generators.Integration.Specs.for_CratisCodeAnalysisPackage;

/// <summary>
/// Verifies that the Cratis.CodeAnalysis umbrella package bundles every Cratis Arc lint analyzer, so a single
/// reference brings the full ARC*/ARCCHR* set.
/// </summary>
public class when_packing_cratis_codeanalysis
{
/// <summary>
/// Verifies that packing Cratis.CodeAnalysis bundles the Arc and Arc.Chronicle analyzer assemblies under
/// analyzers/dotnet/cs.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when packing does not produce a Cratis.CodeAnalysis package.</exception>
[Fact]
public void should_bundle_the_arc_and_chronicle_lint_analyzers()
{
var repositoryRoot = GetRepositoryRoot();
var workingDirectory = Path.Combine(Path.GetTempPath(), "Cratis.CodeAnalysis.Package.Integration", Guid.NewGuid().ToString("N"));
var packageDirectory = Path.Combine(workingDirectory, "packages");

Directory.CreateDirectory(packageDirectory);
RunDotNet(
repositoryRoot,
$"pack \"{Path.Combine(repositoryRoot, "Source", "DotNET", "Cratis.CodeAnalysis", "Cratis.CodeAnalysis.csproj")}\" -c Release --output \"{packageDirectory}\" -p:IncludeSymbols=false -p:IncludeSource=false");

var packagePath = Directory.GetFiles(packageDirectory, "Cratis.CodeAnalysis.*.nupkg", SearchOption.TopDirectoryOnly)
.OrderDescending()
.FirstOrDefault()
?? throw new InvalidOperationException("Expected a packed Cratis.CodeAnalysis nupkg to be created.");

using var package = ZipFile.OpenRead(packagePath);
var analyzerEntries = package.Entries
.Select(_ => _.FullName)
.Where(_ => _.StartsWith("analyzers/dotnet/cs/", StringComparison.Ordinal))
.ToArray();

analyzerEntries.ShouldContain("analyzers/dotnet/cs/Cratis.Arc.Core.CodeAnalysis.dll");
analyzerEntries.ShouldContain("analyzers/dotnet/cs/Cratis.Arc.Chronicle.CodeAnalysis.dll");
}

static string GetRepositoryRoot()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);

while (current is not null)
{
if (File.Exists(Path.Combine(current.FullName, "Arc.slnx")))
{
return current.FullName;
}

current = current.Parent;
}

throw new InvalidOperationException("Could not locate repository root from integration spec output directory.");
}

static void RunDotNet(string workingDirectory, string arguments)
{
using var process = new Process
{
StartInfo = new()
{
FileName = "dotnet",
Arguments = arguments,
WorkingDirectory = workingDirectory,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
}
};

process.Start();
var standardOutputTask = process.StandardOutput.ReadToEndAsync();
var standardErrorTask = process.StandardError.ReadToEndAsync();
process.WaitForExit();
var standardOutput = standardOutputTask.GetAwaiter().GetResult();
var standardError = standardErrorTask.GetAwaiter().GetResult();

if (process.ExitCode != 0)
{
throw new InvalidOperationException($"dotnet {arguments} failed with exit code {process.ExitCode}.{Environment.NewLine}{standardOutput}{Environment.NewLine}{standardError}");
}
}
}
8 changes: 4 additions & 4 deletions Source/DotNET/Arc.Core.Generators/Arc.Core.Generators.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
<TargetFrameworks></TargetFrameworks>
<LangVersion>latest</LangVersion>
<NoWarn>$(NoWarn);NU5128;NU1507</NoWarn>
<!-- This functional source generator ships inside Cratis.Arc.Core (it emits AOT query metadata into the
consumer's assembly), so it must not also be published as a standalone package. Referencing both
would load the same generator twice and fail with CS0101. -->
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
</ItemGroup>

<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
</Project>
38 changes: 38 additions & 0 deletions Source/DotNET/Cratis.CodeAnalysis/Cratis.CodeAnalysis.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Cratis.CodeAnalysis</AssemblyName>
<RootNamespace>Cratis.CodeAnalysis</RootNamespace>
<Description>The full set of Cratis Arc Roslyn analyzers (ARC*, ARCCHR*) in a single reference. Opt in to all the analyzers at once instead of referencing each analyzer package individually.</Description>
<PackageTags>cratis;arc;chronicle;analyzers;roslyn;codeanalysis</PackageTags>
<!-- Analyzer-only package: it ships no runtime assembly, only the bundled analyzer DLLs, and needs no
package dependencies of its own. -->
<IncludeBuildOutput>false</IncludeBuildOutput>
<IncludeSymbols>false</IncludeSymbols>
<IncludeSource>false</IncludeSource>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<DevelopmentDependency>true</DevelopmentDependency>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFrameworks></TargetFrameworks>
<NoWarn>$(NoWarn);NU5128</NoWarn>
</PropertyGroup>

<!-- Build the in-repo lint analyzers first so their assemblies exist to bundle. ReferenceOutputAssembly=false
and PrivateAssets=all keep them off this package's compile/runtime surface and out of its dependencies.
Only the lint analyzers are bundled here — functional source generators (e.g. Cratis.Arc.Core.Generators)
ship with the package they serve, never here, so this umbrella can never collide with a functional
package's generator. -->
<ItemGroup>
<ProjectReference Include="../Arc.Core.CodeAnalysis/Arc.Core.CodeAnalysis.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="all" />
<ProjectReference Include="../Chronicle.CodeAnalysis/Chronicle.CodeAnalysis.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="all" />
</ItemGroup>

<!-- Bundle the lint analyzer assemblies so a single Cratis.CodeAnalysis reference brings the full set. -->
<ItemGroup>
<None Include="../Arc.Core.CodeAnalysis/bin/$(Configuration)/netstandard2.0/Cratis.Arc.Core.CodeAnalysis.dll"
Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<None Include="../Chronicle.CodeAnalysis/bin/$(Configuration)/netstandard2.0/Cratis.Arc.Chronicle.CodeAnalysis.dll"
Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
</Project>
Loading