Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Production Build
BUILD_GRID_VERSION=36.1.0-beta.20260817.956
BUILD_GRID_VERSION=36.1.0-beta.20260818.1041
BUILD_CHARTS_VERSION=14.1.0-beta.20260816
ENV=local
NX_BATCH_MODE=true
Expand Down
9 changes: 7 additions & 2 deletions .github/actions/test-framework-examples/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,16 @@ runs:
working-directory: documentation/ag-grid-docs
env:
PW_BROWSERS: ${{ inputs.browsers == 'all' && 'chromium firefox webkit' || 'chromium' }}
# Bounded + retried via the shared wrapper (AG-18231): `install-deps` shells out to
# `apt-get update`, which has no timeout, so a stalled mirror used to hang the job until
# the 6-hour limit cancelled it. ${GITHUB_WORKSPACE} is needed because this step's
# working-directory is documentation/ag-grid-docs.
run: |
PW_INSTALL="${GITHUB_WORKSPACE}/.github/actions/test-framework-examples/install-playwright.sh"
if [ "${{ steps.pw-cache.outputs.cache-hit }}" = "true" ]; then
npx playwright install-deps ${PW_BROWSERS}
bash "${PW_INSTALL}" deps ${PW_BROWSERS}
else
npx playwright install --with-deps ${PW_BROWSERS}
bash "${PW_INSTALL}" full ${PW_BROWSERS}
fi

# Run Playwright directly via ./docs-e2e.sh (bypasses Nx) so we avoid the Nx target's
Expand Down
74 changes: 74 additions & 0 deletions .github/actions/test-framework-examples/install-playwright.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env bash
# Bounded, retrying Playwright install. `install-deps` / `install --with-deps` shell out to
# `apt-get update`, which has no timeout: when the mirror stalls (AG-18231) the step hangs until
# the 6-hour job limit cancels the job and no test ever runs.
#
# Usage: install-playwright.sh <deps|full|browsers> <browser>...
# deps - `playwright install-deps` (cache hit: OS libraries only; apt)
# full - `playwright install --with-deps` (cache miss: browser download + apt)
# browsers - `playwright install` (browser download only; no apt)
#
# The step must FAIL rather than be cancelled: a job cancelled by `timeout-minutes` makes
# `cancelled()` true and skips the report upload. So the budgets below are sized to give up after
# ~32 min, well inside the 90 min ceiling every doc-tests job now carries. Healthy installs take
# 1-3 min; the bounds are generous because `timeout` cannot tell a stalled mirror from a slow one.
set -uo pipefail

MODE="${1:-}"
shift || true
BROWSERS=("$@")

case "$MODE" in
deps)
CMD=(npx playwright install-deps "${BROWSERS[@]}")
DEFAULT_TIMEOUT=600
DEFAULT_ATTEMPTS=3
LABEL="Playwright OS dependency install (playwright install-deps)"
;;
full)
CMD=(npx playwright install --with-deps "${BROWSERS[@]}")
DEFAULT_TIMEOUT=900
DEFAULT_ATTEMPTS=2
LABEL="Playwright browser + OS dependency install (playwright install --with-deps)"
;;
browsers)
CMD=(npx playwright install "${BROWSERS[@]}")
DEFAULT_TIMEOUT=900
DEFAULT_ATTEMPTS=2
LABEL="Playwright browser download (playwright install)"
;;
*)
echo "::error::install-playwright.sh: unknown mode '${MODE}' (expected deps|full|browsers)"
exit 2
;;
esac

ATTEMPT_TIMEOUT_SECONDS="${PW_INSTALL_TIMEOUT_SECONDS:-${DEFAULT_TIMEOUT}}"
MAX_ATTEMPTS="${PW_INSTALL_MAX_ATTEMPTS:-${DEFAULT_ATTEMPTS}}"
RETRY_DELAY_SECONDS="${PW_INSTALL_RETRY_DELAY_SECONDS:-20}"

for attempt in $(seq 1 "${MAX_ATTEMPTS}"); do
echo "::group::${LABEL} - attempt ${attempt}/${MAX_ATTEMPTS} (bounded to ${ATTEMPT_TIMEOUT_SECONDS}s)"
timeout --signal=TERM --kill-after=30s "${ATTEMPT_TIMEOUT_SECONDS}s" "${CMD[@]}"
status=$?
echo "::endgroup::"

if [ "${status}" -eq 0 ]; then
exit 0
fi

if [ "${status}" -eq 124 ] || [ "${status}" -eq 137 ]; then
reason="did not complete within its ${ATTEMPT_TIMEOUT_SECONDS}s bound and was killed (stalled or very slow package mirror / CDN fetch)"
else
reason="failed with exit code ${status}"
fi
echo "::warning::${LABEL} attempt ${attempt}/${MAX_ATTEMPTS} ${reason}."

if [ "${attempt}" -lt "${MAX_ATTEMPTS}" ]; then
# Give a TERM-ed apt time to release the dpkg/apt lock before retrying.
sleep "${RETRY_DELAY_SECONDS}"
fi
done

echo "::error::${LABEL} did not complete after ${MAX_ATTEMPTS} attempts, each bounded to ${ATTEMPT_TIMEOUT_SECONDS}s. This is an infrastructure failure in the dependency install step - no example tests were run, so it is NOT a test failure."
exit 1
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ jobs:
fail-fast: false
env:
NX_PARALLEL: 1
# Vite 8 warns once per config that these are not loadable by its future `configLoader: 'native'`.
VITE_CONFIG_NATIVE_IGNORE_WARNING: true
steps:
- name: Checkout
id: checkout
Expand Down Expand Up @@ -270,7 +272,7 @@ jobs:
# config emit reports/workspace.xml for this shard.
if: matrix.shard != 0 && needs.init.outputs.unit_projects != ''
id: test
run: npx vitest run ${{ needs.init.outputs.unit_projects }}
run: node_modules/.bin/vitest run ${{ needs.init.outputs.unit_projects }}
--shard=${{ matrix.shard }}/$((${{ strategy.job-total }} - 1))
- name: Type-check test files
# `build:test` (tsc --noEmit on tsconfig.spec) was previously pulled in as the nx `test` target's
Expand Down
16 changes: 14 additions & 2 deletions .github/workflows/doc-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ jobs:
|| github.event.inputs.skip_vue3 != 'true' }}
name: Initialise dependencies
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -122,13 +123,15 @@ jobs:
- name: Install Playwright browsers
if: steps.pw-cache.outputs.cache-hit != 'true'
working-directory: documentation/ag-grid-docs
run: npx playwright install chromium firefox webkit
# Bounded + retried via the shared wrapper; no --with-deps here, so no apt.
run: bash "${GITHUB_WORKSPACE}/.github/actions/test-framework-examples/install-playwright.sh" browsers chromium firefox webkit

test-vanilla:
needs: initialise
if: ${{ github.event.inputs.skip_vanilla != 'true' }}
name: Test vanilla Examples
runs-on: ubuntu-latest
timeout-minutes: 90
# Scoped to the jobs that request the deployed site. At workflow scope the bypass credential would
# also be readable by publish-reports and the third-party actions it runs, which have no need for it.
env:
Expand All @@ -152,6 +155,7 @@ jobs:
if: ${{ github.event.inputs.skip_typescript != 'true' }}
name: Test typescript Examples
runs-on: ubuntu-latest
timeout-minutes: 90
env:
AWS_CI_BYPASS_SECRET: ${{ secrets.AWS_CI_BYPASS_SECRET }}
strategy:
Expand All @@ -173,6 +177,7 @@ jobs:
if: ${{ github.event.inputs.skip_reactFunctionalTs != 'true' }}
name: Test reactFunctionalTs Examples
runs-on: ubuntu-latest
timeout-minutes: 90
env:
AWS_CI_BYPASS_SECRET: ${{ secrets.AWS_CI_BYPASS_SECRET }}
strategy:
Expand All @@ -194,6 +199,7 @@ jobs:
if: ${{ github.event.inputs.skip_vue3 != 'true' }}
name: Test vue3 Examples
runs-on: ubuntu-latest
timeout-minutes: 90
env:
AWS_CI_BYPASS_SECRET: ${{ secrets.AWS_CI_BYPASS_SECRET }}
strategy:
Expand All @@ -215,6 +221,7 @@ jobs:
if: ${{ github.event.inputs.skip_angular != 'true' }}
name: Test angular Examples
runs-on: ubuntu-latest
timeout-minutes: 90
env:
AWS_CI_BYPASS_SECRET: ${{ secrets.AWS_CI_BYPASS_SECRET }}
strategy:
Expand All @@ -236,6 +243,7 @@ jobs:
if: ${{ github.event.inputs.skip_recipes != 'true' }}
name: Test Public Testing Recipes
runs-on: ubuntu-latest
timeout-minutes: 90
strategy:
fail-fast: false
steps:
Expand Down Expand Up @@ -263,15 +271,19 @@ jobs:
publish-reports:
if: always()
needs:
# Without `initialise` here and in IS_SUCCESS, a failure there skips every shard
# ('skipped', not 'failure') and the run reports SUCCESS having run no tests.
- initialise
- test-reactFunctionalTs
- test-angular
- test-typescript
- test-vanilla
- test-vue3
- test-recipes
env:
IS_SUCCESS: ${{ needs.test-angular.result != 'failure' && needs.test-reactFunctionalTs.result != 'failure' && needs.test-typescript.result != 'failure' && needs.test-vanilla.result != 'failure' && needs.test-vue3.result != 'failure' && needs.test-recipes.result != 'failure' }}
IS_SUCCESS: ${{ needs.initialise.result != 'failure' && needs.test-angular.result != 'failure' && needs.test-reactFunctionalTs.result != 'failure' && needs.test-typescript.result != 'failure' && needs.test-vanilla.result != 'failure' && needs.test-vue3.result != 'failure' && needs.test-recipes.result != 'failure' }}
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- uses: actions/checkout@v4
with:
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/gh-comment-hook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
PR_ID: ${{ github.event.pull_request.number }}
PR_URL: ${{ github.event.pull_request.html_url }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
EVENT_ACTION: ${{ github.event.action }}
JIRA_API_AUTH: ${{ secrets.JIRA_API_AUTH }}
JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
Expand All @@ -52,6 +53,7 @@ jobs:
const pr_url = process.env.PR_URL;
const pr_title = process.env.PR_TITLE;
const eventAction = process.env.EVENT_ACTION;
const headRef = process.env.PR_HEAD_REF || '';

// Expand bare JIRA ticket mentions (#AG-XXXX) into markdown links
const body = old_body.replace(/#((AG|RTI)-\d{3,})/g, `[$1](https://ag-grid.atlassian.net/browse/$1)`);
Expand All @@ -65,6 +67,13 @@ jobs:
if (eventAction !== 'opened' && eventAction !== 'edited') return;
if (!process.env.JIRA_API_AUTH) return;

// AI Workflow Delivery PRs post their own JIRA comment once the run is
// actually ready for review, so skip the generic mention comment here.
if (headRef.startsWith('ghabot-ag-')) {
console.log(`Skipping JIRA mention comment for AI workflow PR (branch ${headRef}).`);
return;
}

const { addJiraComment, getJiraIssueComments } =
require('./scripts/ci/_utils.mjs');

Expand Down
64 changes: 64 additions & 0 deletions .github/workflows/github-triage-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ jobs:
# CLAUDE.md § "Auto-chaining browser-verify / repro-rebuild".
issue_key: ${{ steps.pipeline.outputs.issue_key }}
confirmed_bug: ${{ steps.pipeline.outputs.confirmed_bug }}
# NEW (2026-08-18) — confidence-refresh-chain's own gate. See the
# action's CLAUDE.md § "Confidence-gap auto-refresh".
confidence_gap: ${{ steps.pipeline.outputs.confidence_gap }}
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -469,3 +472,64 @@ jobs:
jira_api_token: ${{ secrets.JIRA_AI_BOT_API_TOKEN }}
jira_site_url: ${{ vars.JIRA_SITE_URL }}
jira_ai_bot_account_id: ${{ vars.JIRA_AI_BOT_ACCOUNT_ID }}

# -------------------------------------------------- confidence-refresh-chain (NEW, 2026-08-18)
# Auto-fires ONLY when the ORIGINAL triage recorded an eligible clean-pick
# whose OWN confidence was below the execute threshold (confidence_gap ==
# 'true') — never a decline, never an already-confident pick. Needs ALL
# three prior jobs so the evidence browser-verify-chain/repro-rebuild-chain
# gather (if either ran) is already on the ticket by the time this fires;
# confidence_gap itself comes from `run` alone, so this still fires even
# when browser-verify-chain/repro-rebuild-chain were skipped (e.g. the
# `workflow_dispatch stage=triage` gate on browser-verify-chain not met) —
# a re-triage informed only by what triage itself gathered is still a
# genuine second look, not a no-op.
#
# Rationale + the AITGH-32/37 finding this is built from (including why it
# is NOT a guaranteed confidence bump) are in the action's own CLAUDE.md
# § "Confidence-gap auto-refresh". Same job-graph chaining pattern as the
# two browser stages above — no new event type, no new execution path:
# `resume` still cannot execute on its own regardless of what triggered it.
#
# SECURITY NOTE: same posture as browser-verify-chain/repro-rebuild-chain —
# no dedicated minimal-permission job split yet. This job runs NO browser
# and touches no untrusted repro page directly, but it DOES run the same
# read-only triage/resume agent `run` does, so it inherits `run`'s own
# threat model (an agent reading attacker-authored issue/comment text),
# not the two browser stages' — hence `issues: read` (never write) here
# too, for the same "an unused permission is a mistake" reason as `run`.
confidence-refresh-chain:
needs: [run, browser-verify-chain, repro-rebuild-chain]
if: |
!cancelled() &&
needs.run.outputs.confidence_gap == 'true' &&
(
github.event_name == 'issues'
|| (github.event_name == 'workflow_dispatch' && inputs.stage == 'triage')
)
runs-on: ubuntu-latest
permissions:
contents: read
issues: read
packages: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Install @ag-grid/dev-prompts
uses: ./external/ag-shared/github/actions/install-ag-dev-prompts
with:
channel: ${{ env.DEV_PROMPTS_CHANNEL }}
- uses: ./.ag-dev-prompts/node_modules/@ag-grid/dev-prompts/.github/actions/github-triage-pipeline
with:
stage: resume
trigger: confidence-refresh
product: grid
issue_key: ${{ needs.run.outputs.issue_key }}
channel: ${{ env.DEV_PROMPTS_CHANNEL }}
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
jira_email: ${{ secrets.JIRA_AI_BOT_EMAIL }}
jira_api_token: ${{ secrets.JIRA_AI_BOT_API_TOKEN }}
jira_site_url: ${{ vars.JIRA_SITE_URL }}
jira_ai_bot_account_id: ${{ vars.JIRA_AI_BOT_ACCOUNT_ID }}
Loading
Loading