Skip to content

Extension SDK Compatibility #100

Extension SDK Compatibility

Extension SDK Compatibility #100

name: Extension SDK Compatibility
# Tests that bundled extensions build and pass their MTR suites against the
# SDK at HEAD. Runs automatically after a successful nightly build, and can
# be triggered manually to test a single platform, extension, or ABI variant.
#
# Extension test convention: each extension repo must have a mysql-test/
# directory at its root containing t/ and r/ subdirectories. This directory
# is mounted as mysql-test/suite/<extension-name>/ in the dev server package.
on:
workflow_run:
workflows: ["Nightly Build and Test"]
types: [completed]
branches: [main]
workflow_dispatch:
inputs:
platform:
description: 'Single platform to test (linux-x86_64, linux-aarch64, macos-arm64), or leave empty for all'
required: false
default: ''
extension:
description: 'Single extension to test (e.g. vsql-ai), or leave empty for all'
required: false
default: ''
abi:
description: 'ABI variant to test (stable, dev), or leave empty for both'
required: false
default: ''
ref:
description: 'Branch, tag, or commit SHA to test, or leave empty for the default branch'
required: false
default: ''
notify:
description: 'Send Slack notification with results'
required: false
type: boolean
default: true
permissions:
contents: read
jobs:
# Reads bundled_extensions.txt and builds a cross-product matrix of
# (platform x extension x abi), filtered by any workflow_dispatch inputs.
prepare:
name: Prepare matrix
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
outputs:
build-matrix: ${{ steps.build-matrix.outputs.build-matrix }}
test-matrix: ${{ steps.build-matrix.outputs.test-matrix }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 1
ref: ${{ inputs.ref || github.ref }}
- name: Build test matrix
id: build-matrix
env:
PLATFORM_FILTER: ${{ inputs.platform }}
EXTENSION_FILTER: ${{ inputs.extension }}
ABI_FILTER: ${{ inputs.abi }}
run: |
# Delegate all matrix logic to the script so it can be tested locally:
# PLATFORM_FILTER=macos-arm64 ABI_FILTER=stable \
# ./scripts/villagesql_build-compat-matrix.sh
mapfile -t MATRICES < <(./scripts/villagesql_build-compat-matrix.sh)
BUILD_MATRIX="${MATRICES[0]}"
TEST_MATRIX="${MATRICES[1]}"
COUNT=$(echo "$TEST_MATRIX" | jq '.include | length')
if [ "$COUNT" -eq 0 ]; then
echo "::error::No test jobs matched filters (platform='$PLATFORM_FILTER' extension='$EXTENSION_FILTER' abi='$ABI_FILTER'). Nothing to test."
exit 1
fi
echo "build-matrix=$BUILD_MATRIX" >> "$GITHUB_OUTPUT"
echo "test-matrix=$TEST_MATRIX" >> "$GITHUB_OUTPUT"
# Builds the server (for mysqld + MTR) and SDK (for extension compilation).
# One job per platform; the server binary is ABI-agnostic.
build-server:
name: Build Server (${{ matrix.platform }})
needs: prepare
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.prepare.outputs.build-matrix) }}
env:
BUILD_DIR: ${{ github.workspace }}/build
OUTPUT_DIR: ${{ github.workspace }}/output
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 1
path: source
ref: ${{ inputs.ref || github.ref }}
- name: Install dependencies (Linux)
if: matrix.os == 'linux'
run: sudo source/scripts/setup_linux_build_env.sh
- name: Install dependencies (macOS)
if: matrix.os == 'macos'
run: brew install bison cmake openssl
- name: Cache Boost
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: /tmp/boost
key: boost-${{ runner.os }}-${{ runner.arch }}
- name: Build server and SDK
run: |
mkdir -p "$BUILD_DIR" "$OUTPUT_DIR"
EXTRA_FLAGS="-DDOWNLOAD_BOOST=1 -DWITH_BOOST=/tmp/boost"
if [ "${{ matrix.os }}" = "macos" ]; then
EXTRA_FLAGS="$EXTRA_FLAGS -DWITH_SSL=$(brew --prefix openssl)"
fi
# Build without bundled extensions — each test-extension job builds
# its own extension against the SDK artifact from this job.
BUILD_DIR="$BUILD_DIR" \
OUTPUT_DIR="$OUTPUT_DIR" \
BUILD_BUNDLED_EXTENSIONS=0 \
CMAKE_EXTRA_FLAGS="$EXTRA_FLAGS" \
source/scripts/make_villagesql_dev_server.sh
- name: Upload dev server
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: devserver-${{ matrix.platform }}
path: ${{ env.OUTPUT_DIR }}/*.tar.gz
retention-days: 3
- name: Upload SDK
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sdk-${{ matrix.platform }}
path: ${{ env.BUILD_DIR }}/villagesql-extension-sdk-*.tar.gz
retention-days: 3
# Builds one extension and runs its MTR suite against the dev server.
# Matrix is the cross-product generated by prepare (platform x extension x abi).
test-extension:
name: Test ${{ matrix.extension }} (${{ matrix.platform }}, ${{ matrix.abi }} ABI)
needs: [prepare, build-server]
if: |
needs.build-server.result != 'failure' &&
needs.build-server.result != 'cancelled'
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.prepare.outputs.test-matrix) }}
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 1
sparse-checkout: scripts/
ref: ${{ inputs.ref || github.ref }}
- name: Download dev server
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: devserver-${{ matrix.platform }}
path: artifacts/
- name: Download SDK
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: sdk-${{ matrix.platform }}
path: artifacts/
- name: Extract dev server and SDK
run: |
mkdir -p package sdk
tar xzf artifacts/villagesql-dev-server-*.tar.gz -C package
tar xzf artifacts/villagesql-extension-sdk-*.tar.gz -C sdk
echo "PACKAGE_DIR=$(echo "$PWD"/package/villagesql-dev-server-*)" >> "$GITHUB_ENV"
echo "SDK_DIR=$(echo "$PWD"/sdk/villagesql-extension-sdk-*)" >> "$GITHUB_ENV"
- name: Install build dependencies (Linux)
if: matrix.os == 'linux'
run: sudo ./scripts/setup_linux_ext_deps.sh
- name: Install build dependencies (macOS)
if: matrix.os == 'macos'
run: ./scripts/setup_macos_ext_deps.sh
- name: Clone extension
run: |
CLONE_ARGS=(--depth=1)
[[ -n "${{ matrix.branch }}" ]] && CLONE_ARGS+=(--branch "${{ matrix.branch }}")
git clone "${CLONE_ARGS[@]}" ${{ matrix.url }} extension/
- name: Build extension VEB
run: |
NCORES=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo "4")
DEV_ABI_FLAG=""
[ "${{ matrix.abi }}" = "dev" ] && DEV_ABI_FLAG="-DVSQL_USE_DEV_ABI=ON"
cmake -S extension/ -B ext-build/ \
-DVillageSQL_SDK_DIR="$SDK_DIR" \
-DCMAKE_BUILD_TYPE=Release \
$DEV_ABI_FLAG
cmake --build ext-build/ --parallel "$NCORES"
# Copy the built VEB into the dev server's extension directory
find ext-build/ -maxdepth 1 -name "*.veb" \
-exec cp {} "$PACKAGE_DIR/lib/veb/" \;
- name: Install extension test suite
run: |
if [ ! -d "extension/mysql-test" ]; then
echo "No mysql-test/ directory in ${{ matrix.extension }} — skipping suite install"
exit 0
fi
SUITE_DIR="$PACKAGE_DIR/mysql-test/suite/${{ matrix.extension }}"
mkdir -p "$SUITE_DIR"
cp -r extension/mysql-test/. "$SUITE_DIR/"
- name: Run MTR suite
run: |
if [ ! -d "extension/mysql-test" ]; then
echo "Error: no mysql-test/ directory found in ${{ matrix.extension }}"
exit 1
fi
"$PACKAGE_DIR/villagesql" mysql-test \
--suite=${{ matrix.extension }} \
--parallel=auto \
--nounit-tests \
--force \
--retry=0
- name: Upload MTR results on failure
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: mtr-results-${{ matrix.extension }}-${{ matrix.platform }}-${{ matrix.abi }}
# var/log/ holds the default error log and per-test save dirs; under
# --parallel each worker writes its mysqld.N.err to var/<N>/log/, so
# capture both or the server-side failure reason is lost.
path: |
${{ env.PACKAGE_DIR }}/mysql-test/var/log/
${{ env.PACKAGE_DIR }}/mysql-test/var/*/log/
# Sends a Slack summary after all test jobs complete.
# Runs automatically (workflow_run) or when notify is true (workflow_dispatch).
notify:
name: Slack Notification
needs: [build-server, test-extension]
if: always() && inputs.notify != 'false'
runs-on: ubuntu-latest
steps:
- name: Compute overall status
id: status
run: |
BUILD="${{ needs.build-server.result }}"
TEST="${{ needs.test-extension.result }}"
if [[ "$BUILD" == "success" && "$TEST" == "success" ]]; then
echo "label=passed" >> "$GITHUB_OUTPUT"
echo "emoji=✅" >> "$GITHUB_OUTPUT"
echo "color=#36a64f" >> "$GITHUB_OUTPUT"
elif [[ "$BUILD" == "cancelled" || "$TEST" == "cancelled" ]]; then
echo "label=cancelled" >> "$GITHUB_OUTPUT"
echo "emoji=⚠️" >> "$GITHUB_OUTPUT"
echo "color=#daa520" >> "$GITHUB_OUTPUT"
else
echo "label=failed" >> "$GITHUB_OUTPUT"
echo "emoji=❌" >> "$GITHUB_OUTPUT"
echo "color=#cc0000" >> "$GITHUB_OUTPUT"
fi
- name: Send Slack notification
uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: |
{
"text": "${{ steps.status.outputs.emoji }} Extension SDK Compatibility ${{ steps.status.outputs.label }}",
"attachments": [
{
"color": "${{ steps.status.outputs.color }}",
"fields": [
{
"title": "Run",
"value": "<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View details>",
"short": true
},
{
"title": "Branch",
"value": "${{ github.ref_name }}",
"short": true
},
{
"title": "Triggered by",
"value": "${{ github.event_name }}",
"short": true
},
{
"title": "Build",
"value": "${{ needs.build-server.result }}",
"short": true
},
{
"title": "Tests",
"value": "${{ needs.test-extension.result }}",
"short": true
}
]
}
]
}