diff --git a/.github/workflows/build-arm64.yml b/.github/workflows/build-arm64.yml index 6b8c9a6f99..bb6a3a0237 100644 --- a/.github/workflows/build-arm64.yml +++ b/.github/workflows/build-arm64.yml @@ -25,7 +25,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v5 with: - dotnet-version: 10.0.301 + dotnet-version: 10.0.400 - name: Build Reason env: GITHUB_EVENT: ${{ toJson(github) }} diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 21ecd0eab3..e510d24be3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -240,9 +240,9 @@ jobs: run: | export PATH="$HOME/.dotnet/tools:$PATH" if dotnet tool list --global | grep -Eiq '^aspire\.cli[[:space:]]'; then - dotnet tool update --global Aspire.Cli --version 13.4.6 + dotnet tool update --global Aspire.Cli --version 13.5.0 else - dotnet tool install --global Aspire.Cli --version 13.4.6 + dotnet tool install --global Aspire.Cli --version 13.5.0 fi echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH" aspire --version diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 0809e4fb80..44a0f1886f 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -25,15 +25,15 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v5 with: - dotnet-version: 10.0.301 + dotnet-version: 10.0.400 - name: Install Aspire CLI run: | export PATH="$HOME/.dotnet/tools:$PATH" if dotnet tool list --global | grep -Eiq '^aspire\.cli[[:space:]]'; then - dotnet tool update --global Aspire.Cli --version 13.4.4 + dotnet tool update --global Aspire.Cli --version 13.5.0 else - dotnet tool install --global Aspire.Cli --version 13.4.4 + dotnet tool install --global Aspire.Cli --version 13.5.0 fi echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH" aspire --version diff --git a/.github/workflows/elasticsearch-docker-8.yml b/.github/workflows/elasticsearch-docker-8.yml index 6f65a4ccd6..fe18e066d8 100644 --- a/.github/workflows/elasticsearch-docker-8.yml +++ b/.github/workflows/elasticsearch-docker-8.yml @@ -16,7 +16,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v5 with: - dotnet-version: 10.0.301 + dotnet-version: 10.0.400 - name: Build Reason env: GITHUB_EVENT: ${{ toJson(github) }} diff --git a/Dockerfile b/Dockerfile index 80cc955548..4904cdf6f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:10.0.301 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0.400 AS build ARG MinVerVersionOverride WORKDIR /app @@ -40,7 +40,7 @@ RUN dotnet publish -c Release -o out --no-build # job -FROM mcr.microsoft.com/dotnet/aspnet:10.0.9 AS job +FROM mcr.microsoft.com/dotnet/aspnet:10.0.11 AS job WORKDIR /app COPY --from=job-publish /app/src/Exceptionless.Job/out ./ @@ -59,7 +59,7 @@ RUN dotnet publish -c Release -o out --no-build /p:SkipSpaPublish=true # api -FROM mcr.microsoft.com/dotnet/aspnet:10.0.9 AS api +FROM mcr.microsoft.com/dotnet/aspnet:10.0.11 AS api WORKDIR /app COPY --from=api-publish /app/src/Exceptionless.Web/out ./ @@ -77,7 +77,7 @@ RUN dotnet publish -c Release -o out --no-build # app -FROM mcr.microsoft.com/dotnet/aspnet:10.0.9 AS app +FROM mcr.microsoft.com/dotnet/aspnet:10.0.11 AS app WORKDIR /app COPY --from=app-publish /app/src/Exceptionless.Web/out ./ @@ -151,7 +151,7 @@ USER elasticsearch RUN wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh && \ chmod +x dotnet-install.sh && \ - ./dotnet-install.sh --version 10.0.9 --runtime aspnetcore && \ + ./dotnet-install.sh --version 10.0.11 --runtime aspnetcore && \ rm dotnet-install.sh EXPOSE 8080 9200 diff --git a/src/Exceptionless.AppHost/Exceptionless.AppHost.csproj b/src/Exceptionless.AppHost/Exceptionless.AppHost.csproj index 16cc44ac96..4e3dead578 100644 --- a/src/Exceptionless.AppHost/Exceptionless.AppHost.csproj +++ b/src/Exceptionless.AppHost/Exceptionless.AppHost.csproj @@ -1,17 +1,18 @@ - + Exe net10.0 enable enable a9c2ddcc-e51d-4cd1-9782-96e1d74eec87 + true $(NoWarn);ASPIRECERTIFICATES001 - - - - + + + + diff --git a/src/Exceptionless.AppHost/Extensions/ElasticsearchExtensions.cs b/src/Exceptionless.AppHost/Extensions/ElasticsearchExtensions.cs index ec5c5e4031..c1714d3559 100644 --- a/src/Exceptionless.AppHost/Extensions/ElasticsearchExtensions.cs +++ b/src/Exceptionless.AppHost/Extensions/ElasticsearchExtensions.cs @@ -56,8 +56,7 @@ public static IResourceBuilder AddElasticsearch(this IDis .WithEnvironment("xpack.security.enabled", "false") .WithEnvironment("action.destructive_requires_name", "false") .WithEnvironment("ES_JAVA_OPTS", "-Xms1g -Xmx1g") - .WithHealthCheck(healthCheckKey) - .PublishAsConnectionString(); + .WithHealthCheck(healthCheckKey); } public static IResourceBuilder WithKibana(this IResourceBuilder builder, Action>? configureContainer = null, string? containerName = null) diff --git a/src/Exceptionless.AppHost/Program.cs b/src/Exceptionless.AppHost/Program.cs index b12b48aefe..fb3fc029f8 100644 --- a/src/Exceptionless.AppHost/Program.cs +++ b/src/Exceptionless.AppHost/Program.cs @@ -24,9 +24,32 @@ string exceptionlessServerUrl = worktreePorts?.ApiHttpsUrl ?? $"https://api-ex.dev.localhost:{DefaultApiHttpsPort}"; const string SharedEmailConnectionString = "smtp://localhost:1026"; -var elastic = builder.AddElasticsearch("Elasticsearch", port: 9200) - .WithDataVolume("exceptionless.data.v1") - .WithEndpointProxySupport(false); +IResourceBuilder elastic; +if (builder.ExecutionContext.IsRunMode) +{ + var ownedElastic = builder.AddElasticsearch("Elasticsearch", port: 9200) + .WithDataVolume("exceptionless.data.v1") + .WithEndpointProxySupport(false); + + var localElastic = ownedElastic + .WithLifetime(ContainerLifetime.Persistent) + .WithContainerName("Exceptionless-Elasticsearch"); + + if (!servicesOnly && includeDevTools) + { + localElastic.WithKibana(b => b + .WithLifetime(ContainerLifetime.Persistent) + .WithEndpointProxySupport(false) + .WithContainerName("Exceptionless-Kibana") + .WithParentRelationship(ownedElastic)); + } + + elastic = localElastic; +} +else +{ + elastic = builder.AddConnectionString("Elasticsearch"); +} var storage = builder.AddAzureStorage("Storage") .RunAsEmulator(c => @@ -62,25 +85,11 @@ .WithImageTag("v1.27.10") .WithEndpointProxySupport(false) .WithHttpEndpoint(port: 8026, targetPort: 8025, name: "http") - .WithUrlForEndpoint("http", u => { u.DisplayText = "Mail"; u.DisplayOrder = 100; }) + .WithUrlForEndpoint("http", u => { u.DisplayText = "Mail"; SetDisplayOrder(u, 100); }) .WithHttpHealthCheck("/readyz") .WithEndpoint(targetPort: 1025, port: 1026) .WithUrlForEndpoint("tcp", u => u.DisplayLocation = UrlDisplayLocation.DetailsOnly); -var ownedElastic = elastic; -elastic = ownedElastic - .WithLifetime(ContainerLifetime.Persistent) - .WithContainerName("Exceptionless-Elasticsearch"); - -if (!servicesOnly && includeDevTools) -{ - elastic = elastic.WithKibana(b => b - .WithLifetime(ContainerLifetime.Persistent) - .WithEndpointProxySupport(false) - .WithContainerName("Exceptionless-Kibana") - .WithParentRelationship(ownedElastic)); -} - var ownedCache = cache; cache = ownedCache .WithLifetime(ContainerLifetime.Persistent) @@ -115,7 +124,7 @@ .WaitFor(cache) .WaitFor(mail) .WithExternalHttpEndpoints() - .WithUrlForEndpoint("https", u => { u.DisplayText = "Open API"; u.DisplayOrder = 100; }) + .WithUrlForEndpoint("https", u => { u.DisplayText = "Open API"; SetDisplayOrder(u, 100); }) .WithUrlForEndpoint("http", u => u.DisplayLocation = UrlDisplayLocation.DetailsOnly) .WithHttpHealthCheck("/health"); @@ -161,84 +170,94 @@ .WithEndpoint("http", e => e.Port = worktreePorts.JobsHttp); } -#pragma warning disable ASPIREBROWSERLOGS001 - var oldApp = builder.AddJavaScriptApp("OldApp", "../../src/Exceptionless.Web/ClientApp.angular", "serve") - .WithBrowserLogs() - .WithReference(api) - .WithEnvironment("ASPNETCORE_URLS", oldAppAspNetCoreUrls) - .WithEnvironment("USE_HTTPS", "true") - .WithEnvironment("LIVERELOAD_PORT", oldAppLiveReloadPort.ToString()) - .WithHttpEndpoint(port: oldAppPort, targetPort: oldAppPort, name: "https", env: "PORT", isProxied: false) - .WithEndpoint("https", e => - { - e.TargetHost = "angular-ex.dev.localhost"; - e.UriScheme = "https"; - }) - .WithHttpsDeveloperCertificate() - .WithUrlForEndpoint("https", u => - { - u.DisplayText = "Open App (Old)"; - u.DisplayOrder = 100; - }) - .WithParentRelationship(api); - - if (worktreePorts is not null) + if (builder.ExecutionContext.IsRunMode) { - oldApp.WithEnvironment("API_HTTP", worktreePorts.ApiHttpUrl) - .WithEnvironment("API_HTTPS", worktreePorts.ApiHttpsUrl); - } +#pragma warning disable ASPIREBROWSERLOGS001 + var oldApp = builder.AddJavaScriptApp("OldApp", "../../src/Exceptionless.Web/ClientApp.angular", "serve") + .WithBrowserLogs() + .WithReference(api) + .WithEnvironment("ASPNETCORE_URLS", oldAppAspNetCoreUrls) + .WithEnvironment("USE_HTTPS", "true") + .WithEnvironment("LIVERELOAD_PORT", oldAppLiveReloadPort.ToString()) + .WithHttpEndpoint(port: oldAppPort, targetPort: oldAppPort, name: "https", env: "PORT", isProxied: false) + .WithEndpoint("https", e => + { + e.TargetHost = "angular-ex.dev.localhost"; + e.UriScheme = "https"; + }) + .WithHttpsDeveloperCertificate() + .WithUrlForEndpoint("https", u => + { + u.DisplayText = "Open App (Old)"; + SetDisplayOrder(u, 100); + }) + .WithParentRelationship(api); - var app = builder.AddViteApp("App", "../Exceptionless.Web/ClientApp") - .WithBrowserLogs() - .WithReference(api) - .WithReference(oldApp) - .WithEnvironment("PUBLIC_EXCEPTIONLESS_SERVER_URL", exceptionlessServerUrl) - .WithEnvironment("PORT", appPort.ToString()) - .WithEndpoint("http", e => - { - // 7131 (HTTPS via Aspire dev cert) instead of Vite's default 5173 to avoid clashing with other local Vite projects. - e.Port = appPort; - e.TargetPort = appPort; - e.TargetHost = "web-ex.dev.localhost"; - e.IsProxied = false; - }) - .WithHttpsDeveloperCertificate() - .WithUrlForEndpoint("http", u => + if (worktreePorts is not null) { - u.DisplayText = "Open App"; - u.DisplayOrder = 100; - u.Url = $"{u.Url.TrimEnd('/')}/next/"; - }) - .WithParentRelationship(api); - - if (worktreePorts is not null) - { - app.WithEnvironment("API_HTTP", worktreePorts.ApiHttpUrl) - .WithEnvironment("API_HTTPS", worktreePorts.ApiHttpsUrl) - .WithEnvironment("OLDAPP_HTTP", worktreePorts.OldAppHttpsUrl) - .WithEnvironment("OLDAPP_HTTPS", worktreePorts.OldAppHttpsUrl); - } + oldApp.WithEnvironment("API_HTTP", worktreePorts.ApiHttpUrl) + .WithEnvironment("API_HTTPS", worktreePorts.ApiHttpsUrl); + } - if (includeDevTools) - { - builder.AddDenoTask("Docs", "../../docs", "serve") + var app = builder.AddViteApp("App", "../Exceptionless.Web/ClientApp") .WithBrowserLogs() - .WithHttpEndpoint(port: docsPort, targetPort: docsPort, name: "http", env: "PORT", isProxied: false) + .WithReference(api) + .WithReference(oldApp) + .WithEnvironment("PUBLIC_EXCEPTIONLESS_SERVER_URL", exceptionlessServerUrl) + .WithEnvironment("PORT", appPort.ToString()) .WithEndpoint("http", e => { - e.TargetHost = "localhost"; - e.UriScheme = "http"; + // 7131 (HTTPS via Aspire dev cert) instead of Vite's default 5173 to avoid clashing with other local Vite projects. + e.Port = appPort; + e.TargetPort = appPort; + e.TargetHost = "web-ex.dev.localhost"; + e.IsProxied = false; }) + .WithHttpsDeveloperCertificate() .WithUrlForEndpoint("http", u => { - u.DisplayText = "Open Docs"; - u.DisplayOrder = 100; + u.DisplayText = "Open App"; + SetDisplayOrder(u, 100); + u.Url = $"{u.Url.TrimEnd('/')}/next/"; }) .WithParentRelationship(api); - } + + if (worktreePorts is not null) + { + app.WithEnvironment("API_HTTP", worktreePorts.ApiHttpUrl) + .WithEnvironment("API_HTTPS", worktreePorts.ApiHttpsUrl) + .WithEnvironment("OLDAPP_HTTP", worktreePorts.OldAppHttpsUrl) + .WithEnvironment("OLDAPP_HTTPS", worktreePorts.OldAppHttpsUrl); + } + + if (includeDevTools) + { + builder.AddDenoTask("Docs", "../../docs", "serve") + .WithBrowserLogs() + .WithHttpEndpoint(port: docsPort, targetPort: docsPort, name: "http", env: "PORT", isProxied: false) + .WithEndpoint("http", e => + { + e.TargetHost = "localhost"; + e.UriScheme = "http"; + }) + .WithUrlForEndpoint("http", u => + { + u.DisplayText = "Open Docs"; + SetDisplayOrder(u, 100); + }) + .WithParentRelationship(api); + } #pragma warning restore ASPIREBROWSERLOGS001 + } } await builder.Build().RunAsync(); bool HasArgument(string name) => args.Any(arg => StringComparer.OrdinalIgnoreCase.Equals(arg, name) || StringComparer.OrdinalIgnoreCase.Equals(arg, name.TrimStart('-'))); + +static void SetDisplayOrder(ResourceUrlAnnotation annotation, int displayOrder) +{ +#pragma warning disable CS0618 // Aspire 13.5 temporarily obsoletes this field and plans to restore it as a property. + annotation.DisplayOrder = displayOrder; +#pragma warning restore CS0618 +} diff --git a/tests/Exceptionless.Tests/Exceptionless.Tests.csproj b/tests/Exceptionless.Tests/Exceptionless.Tests.csproj index 6fcf11f7a2..882c75121e 100644 --- a/tests/Exceptionless.Tests/Exceptionless.Tests.csproj +++ b/tests/Exceptionless.Tests/Exceptionless.Tests.csproj @@ -11,7 +11,7 @@ - +