diff --git a/.github/workflows/docs-preview-local.yml b/.github/workflows/docs-preview-local.yml
index 764adb6b51..f322a726da 100644
--- a/.github/workflows/docs-preview-local.yml
+++ b/.github/workflows/docs-preview-local.yml
@@ -189,7 +189,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
- deployments: none
+ deployments: write
id-token: write
pull-requests: none
outputs:
@@ -216,10 +216,8 @@ jobs:
persist-credentials: false
- name: Create Deployment
- # disabled: deployments are not enabled on this branch
if: >
- false
- && env.MATCH == 'true'
+ env.MATCH == 'true'
&& needs.check.outputs.any_modified != 'false'
&& (
github.event_name == 'push'
@@ -363,10 +361,8 @@ jobs:
- name: Update deployment status
uses: actions/github-script@v8
- # disabled: deployments are not enabled on this branch
if: >
- false
- && env.MATCH == 'true'
+ env.MATCH == 'true'
&& always()
&& steps.deployment.outputs.result
env:
@@ -382,3 +378,80 @@ jobs:
environment_url: `https://docs-v3-preview.elastic.dev${process.env.LANDING_PAGE_PATH}`,
log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
})
+
+ comment:
+ if: >
+ github.event_name == 'pull_request'
+ && needs.check.outputs.any_modified == 'true'
+ && needs.build.outputs.path_prefix != ''
+ && needs.build.result == 'success'
+ runs-on: ubuntu-latest
+ needs:
+ - check
+ - build
+ permissions:
+ contents: none
+ deployments: none
+ id-token: none
+ pull-requests: write
+ steps:
+ - name: Comment handbook preview links on PR
+ uses: actions/github-script@v8
+ env:
+ PATH_PREFIX: ${{ needs.build.outputs.path_prefix }}
+ ALL_CHANGED_FILES: ${{ needs.check.outputs.all_changed_files }}
+ with:
+ script: |
+ const title = '## Docs preview (local build)'
+ const base = `https://docs-v3-preview.elastic.dev${process.env.PATH_PREFIX}`
+ const changedMdFiles = process.env.ALL_CHANGED_FILES
+ .split(/\s+/)
+ .filter(Boolean)
+ .filter((i) => i.endsWith('.md'))
+ .filter((i) => !i.includes('/_snippets/'))
+
+ const lines = [title, '', `**Handbook preview:** ${base}/`, '']
+
+ if (changedMdFiles.length > 0) {
+ lines.push('Sample changed pages:')
+ for (const file of changedMdFiles.slice(0, 15)) {
+ const path = file
+ .replace(/^docs\//, '')
+ .replace(/\/index\.md$/, '')
+ .replace(/\.md$/, '')
+ lines.push(`- [${file}](${base}/${path})`)
+ }
+ if (changedMdFiles.length > 15) {
+ lines.push(`- …and ${changedMdFiles.length - 15} more`)
+ }
+ }
+
+ const body = lines.join('\n')
+ const owner = context.repo.owner
+ const repo = context.repo.repo
+ const issue_number = context.payload.pull_request.number
+
+ const { data: comments } = await github.rest.issues.listComments({
+ owner,
+ repo,
+ issue_number,
+ })
+ const existing = comments.find(
+ (c) =>
+ c.user.type === 'Bot' && c.body.startsWith(title)
+ )
+ if (existing) {
+ await github.rest.issues.updateComment({
+ owner,
+ repo,
+ comment_id: existing.id,
+ body,
+ })
+ } else {
+ await github.rest.issues.createComment({
+ owner,
+ repo,
+ issue_number,
+ body,
+ })
+ }
diff --git a/tests-integration/Elastic.Documentation.Api.IntegrationTests/OtlpProxyIntegrationTests.cs b/tests-integration/Elastic.Documentation.Api.IntegrationTests/OtlpProxyIntegrationTests.cs
index 8f5c48dff9..d5ca5472dd 100644
--- a/tests-integration/Elastic.Documentation.Api.IntegrationTests/OtlpProxyIntegrationTests.cs
+++ b/tests-integration/Elastic.Documentation.Api.IntegrationTests/OtlpProxyIntegrationTests.cs
@@ -8,27 +8,24 @@
using Elastic.Documentation.Api.Infrastructure.Adapters.Telemetry;
using Elastic.Documentation.Api.IntegrationTests.Fixtures;
using FakeItEasy;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Elastic.Documentation.Api.IntegrationTests;
-public class OtlpProxyIntegrationTests : IAsyncLifetime
+public class OtlpProxyIntegrationTests
{
private const string OtlpEndpoint = "http://localhost:4318";
- public ValueTask InitializeAsync()
- {
- Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT", OtlpEndpoint);
- return ValueTask.CompletedTask;
- }
-
- public ValueTask DisposeAsync()
- {
- GC.SuppressFinalize(this);
- Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT", null);
- return ValueTask.CompletedTask;
- }
+ ///
+ /// Ensure OTLP routes are mapped by wiring the endpoint into host configuration (same key Program.cs reads).
+ /// Relying only on IAsyncLifetime + env vars is flaky under parallel test execution on CI.
+ ///
+ private static WebApplicationFactory WithOtlpConfigured(WebApplicationFactory factory) =>
+ factory.WithWebHostBuilder(builder =>
+ builder.UseSetting("OTEL_EXPORTER_OTLP_ENDPOINT", OtlpEndpoint));
[Fact]
public async Task OtlpProxyTracesEndpointForwardsToCorrectUrl()
@@ -49,12 +46,12 @@ public async Task OtlpProxyTracesEndpointForwardsToCorrectUrl()
.Invokes((HttpRequestMessage req, CancellationToken ct) => capturedRequest = req)
.Returns(Task.FromResult(mockResponse));
- using var factory = ApiWebApplicationFactory.WithMockedServices(services =>
+ using var factory = WithOtlpConfigured(ApiWebApplicationFactory.WithMockedServices(services =>
{
// Replace the named HttpClient with our mock
_ = services.AddHttpClient(AdotOtlpGateway.HttpClientName)
.ConfigurePrimaryHttpMessageHandler(() => mockHandler);
- });
+ }));
var client = factory.CreateClient();
var otlpPayload = /*lang=json,strict*/ """
@@ -114,11 +111,11 @@ public async Task OtlpProxyLogsEndpointForwardsToCorrectUrl()
.Invokes((HttpRequestMessage req, CancellationToken ct) => capturedRequest = req)
.Returns(Task.FromResult(mockResponse));
- using var factory = ApiWebApplicationFactory.WithMockedServices(services =>
+ using var factory = WithOtlpConfigured(ApiWebApplicationFactory.WithMockedServices(services =>
{
_ = services.AddHttpClient(AdotOtlpGateway.HttpClientName)
.ConfigurePrimaryHttpMessageHandler(() => mockHandler);
- });
+ }));
var client = factory.CreateClient();
var otlpPayload = /*lang=json,strict*/ """
@@ -171,11 +168,11 @@ public async Task OtlpProxyMetricsEndpointForwardsToCorrectUrl()
.Invokes((HttpRequestMessage req, CancellationToken ct) => capturedRequest = req)
.Returns(Task.FromResult(mockResponse));
- using var factory = ApiWebApplicationFactory.WithMockedServices(services =>
+ using var factory = WithOtlpConfigured(ApiWebApplicationFactory.WithMockedServices(services =>
{
_ = services.AddHttpClient(AdotOtlpGateway.HttpClientName)
.ConfigurePrimaryHttpMessageHandler(() => mockHandler);
- });
+ }));
var client = factory.CreateClient();
var otlpPayload = /*lang=json,strict*/ """
@@ -222,14 +219,14 @@ public async Task OtlpProxyReturnsCollectorErrorStatusCode()
.WithReturnType>()
.Returns(Task.FromResult(mockResponse));
- using var factory = ApiWebApplicationFactory.WithMockedServices(services =>
+ using var factory = WithOtlpConfigured(ApiWebApplicationFactory.WithMockedServices(services =>
{
#pragma warning disable EXTEXP0001 // Experimental API - needed for test to bypass resilience handlers
_ = services.AddHttpClient(AdotOtlpGateway.HttpClientName)
.ConfigurePrimaryHttpMessageHandler(() => mockHandler)
.RemoveAllResilienceHandlers();
#pragma warning restore EXTEXP0001
- });
+ }));
var client = factory.CreateClient();
using var content = new StringContent("{}", Encoding.UTF8, "application/json");
@@ -250,7 +247,7 @@ public async Task OtlpProxyReturnsCollectorErrorStatusCode()
public async Task OtlpProxyInvalidSignalTypeReturns404()
{
// Arrange
- using var factory = new ApiWebApplicationFactory();
+ using var factory = WithOtlpConfigured(new ApiWebApplicationFactory());
using var client = factory.CreateClient();
using var content = new StringContent("{}", Encoding.UTF8, "application/json");