feat: add cross-platform release pipeline [CI SKIP]
This commit is contained in:
1 parent
26620707a0
commit
deceeb19f3
27 files changed
+1036
-18
No files matched your search
@@ -5,6 +5,8 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<AnalysisLevel>latest-recommended</AnalysisLevel>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
|
||||
+3
-1
@@ -36,7 +36,9 @@ dotnet test --solution Monitor.slnx
|
||||
dotnet publish src/Monitor.Backend -c Release -r <RID> -p:PublishAot=true
|
||||
```
|
||||
|
||||
例如 `<RID>` 可为 `win-x64`、`linux-x64` 或 `linux-musl-x64`。NativeAOT 发布需要对应平台的 C/C++ 工具链。仓库根目录的 `scripts/publish.sh` 也提供发布和容器构建流程,详见 [`../docs/deployment.md`](../docs/deployment.md)。
|
||||
例如 `<RID>` 可为 `win-x64`、`linux-x64` 或 `linux-arm64`。NativeAOT 发布需要对应平台的 C/C++ 工具链。仓库根目录的 `scripts/publish.sh backend <RID>` 可构建单个平台的 Backend 可执行文件;容器发布由 Woodpecker tag 流水线完成,详见 [`../docs/deployment.md`](../docs/deployment.md)。
|
||||
|
||||
正式发布通过 Woodpecker tag 流水线生成 Linux/amd64 与 Linux/arm64 OCI 镜像,容器内监听 `8080`,数据写入挂载的 `/data` 卷。Agent 与 Probe 的多平台二进制包单独发布,不包含在 Backend 镜像中。
|
||||
|
||||
## 本地运行
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project>
|
||||
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
|
||||
<Import Project="Sdk.props" Sdk="StuDev.AotAnywhere"
|
||||
Condition="'$(RuntimeIdentifier)' == 'linux-x64' Or '$(RuntimeIdentifier)' == 'linux-arm64' Or '$(RuntimeIdentifier)' == 'linux-arm' Or '$(RuntimeIdentifier)' == 'linux-musl-x64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm' Or '$(RuntimeIdentifier)' == 'osx-x64' Or '$(RuntimeIdentifier)' == 'osx-arm64' Or '$(RuntimeIdentifier)' == 'win-x64' Or '$(RuntimeIdentifier)' == 'win-arm64'" />
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AssemblyName>monitor-agent</AssemblyName>
|
||||
@@ -11,4 +14,7 @@
|
||||
<ProjectReference Include="..\..\..\fleet\src\Fleet.Hosting\Fleet.Hosting.csproj" />
|
||||
<ProjectReference Include="..\..\..\shared\Monitor.Measurement\Monitor.Measurement.csproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
|
||||
<Import Project="Sdk.targets" Sdk="StuDev.AotAnywhere"
|
||||
Condition="'$(RuntimeIdentifier)' == 'linux-x64' Or '$(RuntimeIdentifier)' == 'linux-arm64' Or '$(RuntimeIdentifier)' == 'linux-arm' Or '$(RuntimeIdentifier)' == 'linux-musl-x64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm' Or '$(RuntimeIdentifier)' == 'osx-x64' Or '$(RuntimeIdentifier)' == 'osx-arm64' Or '$(RuntimeIdentifier)' == 'win-x64' Or '$(RuntimeIdentifier)' == 'win-arm64'" />
|
||||
</Project>
|
||||
@@ -1,4 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project>
|
||||
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
|
||||
<Import Project="Sdk.props" Sdk="StuDev.AotAnywhere"
|
||||
Condition="'$(RuntimeIdentifier)' == 'linux-x64' Or '$(RuntimeIdentifier)' == 'linux-arm64' Or '$(RuntimeIdentifier)' == 'linux-arm' Or '$(RuntimeIdentifier)' == 'linux-musl-x64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm' Or '$(RuntimeIdentifier)' == 'osx-x64' Or '$(RuntimeIdentifier)' == 'osx-arm64' Or '$(RuntimeIdentifier)' == 'win-x64' Or '$(RuntimeIdentifier)' == 'win-arm64'" />
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AssemblyName>fleet-enroll</AssemblyName>
|
||||
@@ -8,4 +11,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Fleet.Enrollment.Client\Fleet.Enrollment.Client.csproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
|
||||
<Import Project="Sdk.targets" Sdk="StuDev.AotAnywhere"
|
||||
Condition="'$(RuntimeIdentifier)' == 'linux-x64' Or '$(RuntimeIdentifier)' == 'linux-arm64' Or '$(RuntimeIdentifier)' == 'linux-arm' Or '$(RuntimeIdentifier)' == 'linux-musl-x64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm' Or '$(RuntimeIdentifier)' == 'osx-x64' Or '$(RuntimeIdentifier)' == 'osx-arm64' Or '$(RuntimeIdentifier)' == 'win-x64' Or '$(RuntimeIdentifier)' == 'win-arm64'" />
|
||||
</Project>
|
||||
@@ -3,6 +3,9 @@
|
||||
"version": "10.0.200",
|
||||
"rollForward": "latestFeature"
|
||||
},
|
||||
"msbuild-sdks": {
|
||||
"StuDev.AotAnywhere": "1.0.5"
|
||||
},
|
||||
"test": {
|
||||
"runner": "Microsoft.Testing.Platform"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project>
|
||||
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
|
||||
<Import Project="Sdk.props" Sdk="StuDev.AotAnywhere"
|
||||
Condition="'$(RuntimeIdentifier)' == 'linux-x64' Or '$(RuntimeIdentifier)' == 'linux-arm64' Or '$(RuntimeIdentifier)' == 'linux-arm' Or '$(RuntimeIdentifier)' == 'linux-musl-x64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm' Or '$(RuntimeIdentifier)' == 'osx-x64' Or '$(RuntimeIdentifier)' == 'osx-arm64' Or '$(RuntimeIdentifier)' == 'win-x64' Or '$(RuntimeIdentifier)' == 'win-arm64'" />
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AssemblyName>monitor-probe</AssemblyName>
|
||||
@@ -11,4 +14,7 @@
|
||||
<ProjectReference Include="..\..\..\fleet\src\Fleet.Hosting\Fleet.Hosting.csproj" />
|
||||
<ProjectReference Include="..\..\..\shared\Monitor.Measurement\Monitor.Measurement.csproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
|
||||
<Import Project="Sdk.targets" Sdk="StuDev.AotAnywhere"
|
||||
Condition="'$(RuntimeIdentifier)' == 'linux-x64' Or '$(RuntimeIdentifier)' == 'linux-arm64' Or '$(RuntimeIdentifier)' == 'linux-arm' Or '$(RuntimeIdentifier)' == 'linux-musl-x64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm64' Or '$(RuntimeIdentifier)' == 'linux-musl-arm' Or '$(RuntimeIdentifier)' == 'osx-x64' Or '$(RuntimeIdentifier)' == 'osx-arm64' Or '$(RuntimeIdentifier)' == 'win-x64' Or '$(RuntimeIdentifier)' == 'win-arm64'" />
|
||||
</Project>
|
||||
@@ -252,9 +252,32 @@ public sealed class AgentEndToEndTests
|
||||
await using ProbeSimulator probe = await agent.ConnectProbeAsync();
|
||||
await BackendFixture.EventuallyAsync(async () => (await AgentViewAsync(agent))["probe_connected"]!.GetValue<bool>());
|
||||
|
||||
using HttpResponseMessage accepted = await _backend.Admin.PostAsync($"/api/admin/lines/{agent.Id}~{probe.ProbeId}/tests", BackendFixture.Json(new JsonObject { ["plan"] = "hy2_ladder", ["params"] = new JsonObject { ["size"] = 1000 } }));
|
||||
Assert.True(accepted.StatusCode == System.Net.HttpStatusCode.Accepted, await accepted.Content.ReadAsStringAsync());
|
||||
string testId = JsonNode.Parse(await accepted.Content.ReadAsStringAsync())!["id"]!.GetValue<string>();
|
||||
HttpResponseMessage? accepted = null;
|
||||
string? startFailure = null;
|
||||
for (int attempt = 0; attempt < 5; attempt++)
|
||||
{
|
||||
accepted = await _backend.Admin.PostAsync($"/api/admin/lines/{agent.Id}~{probe.ProbeId}/tests", BackendFixture.Json(new JsonObject { ["plan"] = "hy2_ladder", ["params"] = new JsonObject { ["size"] = 1000 } }));
|
||||
if (accepted.StatusCode == System.Net.HttpStatusCode.Accepted)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
startFailure = await accepted.Content.ReadAsStringAsync();
|
||||
string? code = JsonNode.Parse(startFailure)?["code"]?.GetValue<string>();
|
||||
accepted.Dispose();
|
||||
accepted = null;
|
||||
if (code != "probe_offline" || attempt == 4)
|
||||
{
|
||||
Assert.Fail($"The test request was rejected: {startFailure}");
|
||||
}
|
||||
|
||||
await BackendFixture.EventuallyAsync(async () => (await AgentViewAsync(agent))["probe_connected"]!.GetValue<bool>(), TimeSpan.FromSeconds(15), "the probe should reconnect after a transient disconnect");
|
||||
}
|
||||
|
||||
HttpResponseMessage acceptedResponse = accepted ?? throw new InvalidOperationException("The test request was not accepted.");
|
||||
using (acceptedResponse)
|
||||
{
|
||||
string testId = JsonNode.Parse(await acceptedResponse.Content.ReadAsStringAsync())!["id"]!.GetValue<string>();
|
||||
|
||||
JsonNode test = null!;
|
||||
await BackendFixture.EventuallyAsync(
|
||||
@@ -273,6 +296,7 @@ public sealed class AgentEndToEndTests
|
||||
await BackendFixture.EventuallyAsync(
|
||||
async () => (await _backend.GetJsonAsync(_backend.Admin, $"/api/admin/raw/chunks?agent_id={agent.Id}"))["items"]!.AsArray().Count(c => c!["kind"]!.GetValue<string>() == "udp_train") == agent.App.Counters.Fragments,
|
||||
because: (await _backend.GetJsonAsync(_backend.Admin, $"/api/admin/events?agent_id={agent.Id}")).ToJsonString() + $" fragments={agent.App.Counters.Fragments} discarded={agent.App.Counters.FragmentsDiscarded} pending={agent.App.Link.Outbox.PendingCount}/{agent.App.Link.Outbox.PendingBytes} dropped={agent.App.Link.Outbox.Dropped} link={agent.App.Link.IsConnected}");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -199,3 +199,6 @@ public sealed class ApiBasicsTests
|
||||
|
||||
[CollectionDefinition("backend")]
|
||||
public sealed class BackendCollection : ICollectionFixture<BackendFixture>;
|
||||
|
||||
[CollectionDefinition("probe-e2e")]
|
||||
public sealed class ProbeEndToEndCollection : ICollectionFixture<BackendFixture>;
|
||||
@@ -36,10 +36,13 @@ public sealed class ArchitectureTests
|
||||
Path.GetFileNameWithoutExtension(path),
|
||||
path,
|
||||
Path.GetDirectoryName(path)!,
|
||||
[.. items.Where(e => e.Name == "ProjectReference").Select(e => Path.GetFileNameWithoutExtension((string?)e.Attribute("Include") ?? ""))],
|
||||
[.. items.Where(e => e.Name == "ProjectReference").Select(e => Path.GetFileNameWithoutExtension(NormalizePath((string?)e.Attribute("Include") ?? "")))],
|
||||
[.. items.Where(e => e.Name == "PackageReference").Select(e => (string?)e.Attribute("Include") ?? "")]);
|
||||
})];
|
||||
|
||||
private static string NormalizePath(string path) =>
|
||||
path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
private static bool IsTest(Project p) => p.Path.Contains(Path.DirectorySeparatorChar + "tests" + Path.DirectorySeparatorChar, StringComparison.Ordinal);
|
||||
|
||||
private static bool IsFleet(Project p) => p.Name.StartsWith("Fleet.", StringComparison.Ordinal) && !IsTest(p);
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text.Json.Nodes;
|
||||
namespace Monitor.Backend.Tests;
|
||||
|
||||
/// <summary>真实的后端 + 真实的 Agent + 真实的 Probe(都在进程内,回环网络)。</summary>
|
||||
[Collection("backend")]
|
||||
[Collection("probe-e2e")]
|
||||
public sealed class ProbeEndToEndTests
|
||||
{
|
||||
private readonly BackendFixture _backend;
|
||||
|
||||
Reference in new issue
Block a user