fix(archreview): CI pipeline + codegen freshness guards (IPC-01/09/19/20, TST-03)
- IPC-01: regenerate the stale client descriptor set and add ClientProtoInputTests (semantic, protoc-free) so a missing contract symbol fails the build. - IPC-20: make publish-client-proto-inputs.ps1 -Check source_code_info-normalized so it is protoc-version tolerant. - IPC-19: document + guard the "Generated/ must be committed for net48" rule (docs/Contracts.md, csproj comment, check-codegen.ps1). - IPC-09: harden the per-client generate-proto scripts (PATH resolution + pinned grpcio/protobuf/java version asserts) so regeneration is reproducible. - TST-03: add .gitea/workflows/ci.yml (portable/java/windows/live jobs) running the build, tests, client checks, and the codegen guards. - Also: check-codegen.ps1 Check 3 guards the CLI-02 vendored Rust protos against drift. archreview: IPC-01/09/19/20 Done, TST-03 In review (pipeline authored + validated, not yet run on a Gitea runner). Verified on macOS: NonWindows build clean, ClientProtoInputTests 5/5, -Check exit 0.
This commit is contained in:
@@ -23,6 +23,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Generated\**\*.cs is Compile-Removed and regenerated by Grpc.Tools into the TRACKED Generated
|
||||
folder. It MUST be committed after any .proto change: Grpc.Tools skips regeneration when the
|
||||
committed output looks up to date, so on net10 the freshly regenerated code compiles (drift is
|
||||
invisible) while the net48 worker, which consumes the COMMITTED Generated\*.cs, fails with
|
||||
CS0246 on new types. Regenerate + commit after editing a .proto; if a build does not pick up
|
||||
the change, delete Generated\*.cs to force a full regen. scripts/check-codegen.ps1 enforces
|
||||
this in CI. See docs/Contracts.md. -->
|
||||
<Compile Remove="Generated\**\*.cs" />
|
||||
<Protobuf Include="Protos\mxaccess_gateway.proto" ProtoRoot="Protos" OutputDir="Generated" GrpcOutputDir="Generated" GrpcServices="Both" />
|
||||
<Protobuf Include="Protos\mxaccess_worker.proto" ProtoRoot="Protos" OutputDir="Generated" GrpcServices="None" />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Text.Json;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.Reflection;
|
||||
using ZB.MOM.WW.MxGateway.Contracts;
|
||||
using ZB.MOM.WW.MxGateway.Contracts.Proto;
|
||||
|
||||
@@ -7,6 +8,102 @@ namespace ZB.MOM.WW.MxGateway.Tests.Contracts;
|
||||
|
||||
public sealed class ClientProtoInputTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Guards the published client descriptor set against silent staleness (IPC-01). Every message
|
||||
/// and field compiled into the in-process contract (which the build regenerates from the current
|
||||
/// <c>.proto</c> sources) must appear in the committed protoset. A missing symbol means the
|
||||
/// descriptor was not regenerated after a proto change; run
|
||||
/// <c>scripts/publish-client-proto-inputs.ps1</c> and commit the refreshed protoset.
|
||||
/// The check is semantic (symbol presence) rather than byte-wise, so it is independent of protoc
|
||||
/// version and does not require protoc on the test runner.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Descriptor_ContainsEveryContractMessageAndField()
|
||||
{
|
||||
DirectoryInfo repositoryRoot = FindRepositoryRoot();
|
||||
string descriptorPath = Path.Combine(
|
||||
repositoryRoot.FullName,
|
||||
"clients",
|
||||
"proto",
|
||||
"descriptors",
|
||||
"mxaccessgw-client-v1.protoset");
|
||||
|
||||
Assert.True(File.Exists(descriptorPath), $"Expected descriptor set '{descriptorPath}' to exist.");
|
||||
|
||||
FileDescriptorSet descriptorSet = FileDescriptorSet.Parser.ParseFrom(File.ReadAllBytes(descriptorPath));
|
||||
|
||||
HashSet<string> publishedMessages = new(StringComparer.Ordinal);
|
||||
HashSet<string> publishedFields = new(StringComparer.Ordinal);
|
||||
foreach (FileDescriptorProto file in descriptorSet.File)
|
||||
{
|
||||
foreach (DescriptorProto message in file.MessageType)
|
||||
{
|
||||
CollectPublishedSymbols(file.Package, message, publishedMessages, publishedFields);
|
||||
}
|
||||
}
|
||||
|
||||
List<string> missing = [];
|
||||
foreach (FileDescriptor file in new[] { MxaccessGatewayReflection.Descriptor, MxaccessWorkerReflection.Descriptor })
|
||||
{
|
||||
foreach (MessageDescriptor message in file.MessageTypes)
|
||||
{
|
||||
CollectMissingContractSymbols(message, publishedMessages, publishedFields, missing);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.True(
|
||||
missing.Count == 0,
|
||||
"Published client descriptor is stale; regenerate with scripts/publish-client-proto-inputs.ps1 and commit. "
|
||||
+ "Missing symbols: "
|
||||
+ string.Join(", ", missing));
|
||||
}
|
||||
|
||||
private static void CollectPublishedSymbols(
|
||||
string package,
|
||||
DescriptorProto message,
|
||||
HashSet<string> messages,
|
||||
HashSet<string> fields)
|
||||
{
|
||||
string fullName = string.IsNullOrEmpty(package) ? message.Name : package + "." + message.Name;
|
||||
messages.Add(fullName);
|
||||
|
||||
foreach (FieldDescriptorProto field in message.Field)
|
||||
{
|
||||
fields.Add(fullName + "/" + field.Name);
|
||||
}
|
||||
|
||||
foreach (DescriptorProto nested in message.NestedType)
|
||||
{
|
||||
CollectPublishedSymbols(fullName, nested, messages, fields);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectMissingContractSymbols(
|
||||
MessageDescriptor message,
|
||||
HashSet<string> publishedMessages,
|
||||
HashSet<string> publishedFields,
|
||||
List<string> missing)
|
||||
{
|
||||
if (!publishedMessages.Contains(message.FullName))
|
||||
{
|
||||
missing.Add(message.FullName);
|
||||
}
|
||||
|
||||
foreach (FieldDescriptor field in message.Fields.InDeclarationOrder())
|
||||
{
|
||||
string key = message.FullName + "/" + field.Name;
|
||||
if (!publishedFields.Contains(key))
|
||||
{
|
||||
missing.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MessageDescriptor nested in message.NestedTypes)
|
||||
{
|
||||
CollectMissingContractSymbols(nested, publishedMessages, publishedFields, missing);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the proto inputs manifest declares current protocol versions and existing source files.</summary>
|
||||
[Fact]
|
||||
public void Manifest_DeclaresCurrentProtocolVersionsAndExistingInputs()
|
||||
|
||||
Reference in New Issue
Block a user