Skip to content

Serverless changelog - April 29, 2026 #202

Serverless changelog - April 29, 2026

Serverless changelog - April 29, 2026 #202

Workflow file for this run

name: Docs AI menu
on:
issues:
types: [opened]
issue_comment:
types: [edited]
workflow_dispatch:
inputs:
issue_number:
description: Issue number to post or refresh the AI menu on.
required: true
type: string
permissions:
contents: read
issues: write
jobs:
post-menu:
name: Post or refresh AI menu
if: github.event_name == 'issues' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
concurrency:
group: docs-ai-menu-${{ github.event.issue.number || github.event.inputs.issue_number }}
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@v6.0.2
with:
persist-credentials: false
- name: Create or update AI menu comment
uses: actions/github-script@v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const menu = require(`${process.env.GITHUB_WORKSPACE}/.github/scripts/docs_ai_menu.cjs`);
const workflowDispatchIssueNumber = context.payload.inputs?.issue_number;
const issueNumber = context.eventName === 'workflow_dispatch'
? Number(workflowDispatchIssueNumber)
: context.payload.issue.number;
if (!issueNumber) {
core.setFailed('Issue number is required for workflow_dispatch runs.');
return;
}
await menu.upsertMenuComment({ core, github, context, issueNumber });
evaluate-trigger:
name: Evaluate AI menu trigger
if: >-
github.event_name == 'issue_comment' &&
github.event.issue.pull_request == null &&
github.actor != 'github-actions[bot]' &&
github.event.comment.user.login == 'github-actions[bot]' &&
contains(github.event.comment.body, '<!-- docs-ai-menu:start -->') &&
contains(github.event.comment.body, '<!-- docs-ai-menu:end -->')
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
triage_triggered: ${{ steps.evaluate.outputs.triage_triggered }}
issue_scope_triggered: ${{ steps.evaluate.outputs.issue_scope_triggered }}
steps:
- name: Checkout repository
uses: actions/checkout@v6.0.2
with:
persist-credentials: false
- name: Parse AI menu transition
id: evaluate
uses: actions/github-script@v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const menu = require(`${process.env.GITHUB_WORKSPACE}/.github/scripts/docs_ai_menu.cjs`);
const body = context.payload.comment.body || '';
const previousBody = context.payload.changes?.body?.from || '';
const previousState = menu.parseMenuState(previousBody);
const currentState = menu.parseMenuState(body);
const triageTriggered = !previousState.triage.selected && currentState.triage.selected;
const issueScopeTriggered = !previousState.issueScope.selected && currentState.issueScope.selected;
core.setOutput('triage_triggered', String(triageTriggered));
core.setOutput('issue_scope_triggered', String(issueScopeTriggered));
refresh-menu-after-trigger:
name: Refresh AI menu after trigger
needs: [evaluate-trigger]
if: >-
needs.evaluate-trigger.outputs.triage_triggered == 'true' ||
needs.evaluate-trigger.outputs.issue_scope_triggered == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
concurrency:
group: docs-ai-menu-${{ github.event.issue.number }}
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@v6.0.2
with:
persist-credentials: false
- name: Refresh AI menu status
uses: actions/github-script@v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const menu = require(`${process.env.GITHUB_WORKSPACE}/.github/scripts/docs_ai_menu.cjs`);
const issueNumber = context.payload.issue.number;
const progressUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const statusOverrides = {};
if ('${{ needs.evaluate-trigger.outputs.triage_triggered }}' === 'true') {
statusOverrides.triage = {
detailsUrl: progressUrl,
status: 'in_progress',
};
}
if ('${{ needs.evaluate-trigger.outputs.issue_scope_triggered }}' === 'true') {
statusOverrides.issueScope = {
detailsUrl: progressUrl,
status: 'in_progress',
};
}
await menu.upsertMenuComment({
core,
createIfMissing: false,
github,
context,
issueNumber,
statusOverrides,
});
run-docs-triage:
name: Docs AI / triage
needs: [evaluate-trigger]
if: needs.evaluate-trigger.outputs.triage_triggered == 'true'
permissions:
actions: read
contents: read
discussions: write
issues: write
pull-requests: write
uses: elastic/docs-actions/.github/workflows/gh-aw-issue-triage.lock.yml@v1
with:
additional-instructions: |
## Team Ownership Mapping
This mapping is derived from the repository's CODEOWNERS file. Use it to determine which team owns each issue. Match based on the issue title, body, any mentioned URLs, and labels.
| Team Label | Owns | Keywords / URL paths |
|---|---|---|
| `Team:Admin` | Elasticsearch admin, cluster mgmt, cloud, deployment docs | Cluster management, index management, auth, roles, API keys, network security, cluster security, snapshots, ILM, data lifecycle, CCR, CCS, licensing, subscriptions, upgrade, monitoring, Elastic Cloud, ECE, ECK, serverless. Paths: `deploy-manage/`, `cloud-account/`, `manage-data/` (except `manage-data/ingest/`), `serverless/`, `troubleshoot/deployments/`, `troubleshoot/elasticsearch/` |
| `Team:Experience` | Kibana, observability solution, security solution | Kibana, dashboards, visualizations, Discover, observability, security, APM UI, maps, canvas, Lens, alerting, rules, cases, SIEM, endpoint security, detection rules, security analytics. Paths: `explore-analyze/` (default), `solutions/observability/`, `solutions/security/`, `reference/kibana/`, `reference/observability/`, `reference/security/` |
| `Team:Developer` | Elasticsearch developer, search solution docs | Elasticsearch APIs, ES|QL, query DSL, search features, relevance, vector search, semantic search, inference APIs, connectors, developer tools, clients, search applications, App Search, Workplace Search. Paths: `solutions/search/`, `reference/elasticsearch/clients/`, `reference/search/`, `reference/machine-learning/`, `explore-analyze/ai-features/`, `explore-analyze/cross-cluster-search/`, `explore-analyze/cross-project-search/`, `explore-analyze/transforms/` |
| `Team:Ingest` | Data ingestion, Fleet, APM agents docs | Fleet, Elastic Agent, Beats, Logstash, pipelines, integrations, data streams, APM agents, APM server, OpenTelemetry. Paths: `manage-data/ingest/`, `reference/apm-agents/`, `reference/fleet/`, `reference/ingestion-tools/`, `solutions/observability/apm/apm-agents/`, `solutions/observability/apm/apm-server/`, `solutions/observability/apm/ingest/`, `solutions/observability/apm/opentelemetry/` |
| `Team:DocsEng` | Docs infrastructure | Docs build system, CI/CD, website rendering, broken navigation, docs-builder bugs, elastic.co website issues not related to content. Paths: `.github/workflows/`, `.github/scripts/` |
| `Team:Projects` | Internal projects, docs initiatives | Internal documentation projects, content strategy, information architecture, get-started guides. Paths: `get-started/` |
**Shared ownership**: Some paths have shared ownership (e.g., `/explore-analyze/machine-learning/` is shared by Developer and Experience). Pick the team whose keywords best match the issue content.
**Internal projects**: If the issue seems related to an internal documentation project, initiative, or content strategy effort, apply `Team:Projects`.
**Fallback**: If you genuinely cannot determine the owning team, apply `cross-team` so the issue stays visible to all teams.
secrets:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
run-docs-issue-scope:
name: Docs AI / issue scope
needs: [evaluate-trigger]
if: needs.evaluate-trigger.outputs.issue_scope_triggered == 'true'
permissions:
actions: read
contents: read
discussions: write
issues: write
pull-requests: write
uses: elastic/docs-actions/.github/workflows/gh-aw-docs-issue-scope.lock.yml@v1
secrets:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
refresh-menu-after-docs-triage:
name: Refresh AI menu after docs triage
needs: [evaluate-trigger, refresh-menu-after-trigger, run-docs-triage]
if: always() && needs.evaluate-trigger.outputs.triage_triggered == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
concurrency:
group: docs-ai-menu-${{ github.event.issue.number }}
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@v6.0.2
with:
persist-credentials: false
- name: Refresh AI menu status
uses: actions/github-script@v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const menu = require(`${process.env.GITHUB_WORKSPACE}/.github/scripts/docs_ai_menu.cjs`);
const issueNumber = context.payload.issue.number;
const progressUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const triageResult = '${{ needs.run-docs-triage.result }}';
await menu.upsertMenuComment({
core,
createIfMissing: false,
github,
context,
issueNumber,
statusOverrides: {
triage: {
conclusion: triageResult === 'success'
? 'success'
: triageResult === 'cancelled'
? 'cancelled'
: 'failure',
detailsUrl: progressUrl,
status: 'completed',
},
},
});
refresh-menu-after-docs-issue-scope:
name: Refresh AI menu after docs issue scope
needs: [evaluate-trigger, refresh-menu-after-trigger, run-docs-issue-scope]
if: always() && needs.evaluate-trigger.outputs.issue_scope_triggered == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
concurrency:
group: docs-ai-menu-${{ github.event.issue.number }}
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@v6.0.2
with:
persist-credentials: false
- name: Refresh AI menu status
uses: actions/github-script@v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const menu = require(`${process.env.GITHUB_WORKSPACE}/.github/scripts/docs_ai_menu.cjs`);
const issueNumber = context.payload.issue.number;
const progressUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const issueScopeResult = '${{ needs.run-docs-issue-scope.result }}';
await menu.upsertMenuComment({
core,
createIfMissing: false,
github,
context,
issueNumber,
statusOverrides: {
issueScope: {
conclusion: issueScopeResult === 'success'
? 'success'
: issueScopeResult === 'cancelled'
? 'cancelled'
: 'failure',
detailsUrl: progressUrl,
status: 'completed',
},
},
});