Extension SDK Compatibility #100
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | |
| } | |
| ] | |
| } | |
| ] | |
| } |