From bdb0918ea79ae72647caa21c491d1c99f8cfed7b Mon Sep 17 00:00:00 2001 From: Ophir LOJKINE Date: Wed, 7 Oct 2026 23:14:08 +0200 Subject: [PATCH 1/4] ci: map Hurl suites in workflow YAML --- .github/workflows/ci.yml | 65 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b72e4e7f..f50c4947 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -333,22 +333,81 @@ jobs: retention-days: 1 hurl_examples: runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + env: + DIFF_BASE: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }} + DIFF_HEAD: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha || github.sha }} outputs: examples: ${{ steps.examples.outputs.examples }} steps: - uses: actions/checkout@v7 + with: + fetch-depth: 0 + - id: paths + name: Match changed paths to Hurl suites + uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 + if: ${{ github.ref_type != 'tag' && env.DIFF_BASE != '' && !startsWith(env.DIFF_BASE, '0000000') }} + continue-on-error: true + with: + base: ${{ env.DIFF_BASE }} + ref: ${{ env.DIFF_HEAD }} + filters: | + all_examples: + - 'examples/**' + - 'Dockerfile' + - '.dockerignore' + - 'Cargo.toml' + - 'Cargo.lock' + - 'build.rs' + - '.cargo/**' + - 'scripts/**' + - '.github/workflows/ci.yml' + telemetry: + - 'src/telemetry.rs' + - 'src/main.rs' + - 'src/webserver/http.rs' + - 'src/webserver/database/execute_queries.rs' + smtp: + - 'src/app_config.rs' + - 'src/webserver/database/sqlpage_functions/functions/send_mail.rs' - id: examples + name: Select relevant Hurl examples + shell: bash run: | - examples="$(find examples -mindepth 2 -maxdepth 2 -name test.hurl -print | sed 's#/test.hurl$##' | sort | jq -R -s -c 'split("\n")[:-1]')" + set -euo pipefail + if [[ "$GITHUB_REF_TYPE" == tag \ + || "${{ steps.paths.outcome }}" != success \ + || "${{ steps.paths.outputs.all_examples }}" == true ]]; then + examples="$(find examples -mindepth 2 -maxdepth 2 -name test.hurl -print \ + | sed 's#/test.hurl$##' \ + | sort \ + | jq -R -s -c 'split("\n")[:-1]')" + else + examples="$(jq -nc \ + --arg telemetry "${{ steps.paths.outputs.telemetry }}" \ + --arg smtp "${{ steps.paths.outputs.smtp }}" \ + '[ + (if $telemetry == "true" then "examples/telemetry" else empty end), + (if $smtp == "true" then "examples/sending emails" else empty end) + ]')" + fi echo "examples=$examples" >> "$GITHUB_OUTPUT" + if [[ "$examples" == '[]' ]]; then + echo 'No Hurl examples match these changes; Rust and Playwright checks still run.' >> "$GITHUB_STEP_SUMMARY" + else + echo "Selected Hurl examples: $examples" >> "$GITHUB_STEP_SUMMARY" + fi - name: Restore Hurl archive id: hurl-cache + if: steps.examples.outputs.examples != '[]' uses: actions/cache@v6 with: path: .cache/hurl key: hurl-${{ runner.os }}-x86_64-unknown-linux-gnu-${{ env.HURL_VERSION }} - name: Download Hurl archive - if: steps.hurl-cache.outputs.cache-hit != 'true' + if: steps.examples.outputs.examples != '[]' && steps.hurl-cache.outputs.cache-hit != 'true' run: | set -euo pipefail archive="hurl-${HURL_VERSION}-x86_64-unknown-linux-gnu.tar.gz" @@ -363,6 +422,7 @@ jobs: test "$expected_sha" = "$actual_sha" ) - name: Upload Hurl archive + if: steps.examples.outputs.examples != '[]' uses: actions/upload-artifact@v7 with: name: hurl-${{ env.HURL_VERSION }}-x86_64-unknown-linux-gnu @@ -373,6 +433,7 @@ jobs: hurl: name: hurl (${{ matrix.example }}) runs-on: ubuntu-latest + if: ${{ needs.hurl_examples.outputs.examples != '[]' }} timeout-minutes: 15 needs: - docker_build From 80cdff2d81995b4d5c0a50a0b83e8db589706a7e Mon Sep 17 00:00:00 2001 From: Ophir Lojkine Date: Thu, 8 Oct 2026 10:56:23 +0000 Subject: [PATCH 2/4] ci: simplify Hurl example selection --- .github/hurl-examples.yml | 22 ++++++++++++++ .github/workflows/ci.yml | 53 +++++---------------------------- scripts/select-hurl-examples.sh | 13 ++++++++ 3 files changed, 42 insertions(+), 46 deletions(-) create mode 100644 .github/hurl-examples.yml create mode 100755 scripts/select-hurl-examples.sh diff --git a/.github/hurl-examples.yml b/.github/hurl-examples.yml new file mode 100644 index 00000000..9b42762e --- /dev/null +++ b/.github/hurl-examples.yml @@ -0,0 +1,22 @@ +# Shared changes run every examples/*/test.hurl, including newly added examples. +all_examples: + - 'examples/**' + - 'Dockerfile' + - '.dockerignore' + - 'Cargo.toml' + - 'Cargo.lock' + - 'build.rs' + - '.cargo/**' + - 'scripts/**' + - '.github/workflows/ci.yml' + - '.github/hurl-examples.yml' + +# Keys are example folders; add one glob per line to associate more files. +'examples/telemetry': + - 'src/telemetry.rs' + - 'src/main.rs' + - 'src/webserver/http.rs' + - 'src/webserver/database/execute_queries.rs' +'examples/sending emails': + - 'src/app_config.rs' + - 'src/webserver/database/sqlpage_functions/functions/send_mail.rs' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f50c4947..5db2d07f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -338,7 +338,6 @@ jobs: pull-requests: read env: DIFF_BASE: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }} - DIFF_HEAD: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha || github.sha }} outputs: examples: ${{ steps.examples.outputs.examples }} steps: @@ -352,53 +351,15 @@ jobs: continue-on-error: true with: base: ${{ env.DIFF_BASE }} - ref: ${{ env.DIFF_HEAD }} - filters: | - all_examples: - - 'examples/**' - - 'Dockerfile' - - '.dockerignore' - - 'Cargo.toml' - - 'Cargo.lock' - - 'build.rs' - - '.cargo/**' - - 'scripts/**' - - '.github/workflows/ci.yml' - telemetry: - - 'src/telemetry.rs' - - 'src/main.rs' - - 'src/webserver/http.rs' - - 'src/webserver/database/execute_queries.rs' - smtp: - - 'src/app_config.rs' - - 'src/webserver/database/sqlpage_functions/functions/send_mail.rs' + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha || github.sha }} + filters: .github/hurl-examples.yml - id: examples name: Select relevant Hurl examples - shell: bash - run: | - set -euo pipefail - if [[ "$GITHUB_REF_TYPE" == tag \ - || "${{ steps.paths.outcome }}" != success \ - || "${{ steps.paths.outputs.all_examples }}" == true ]]; then - examples="$(find examples -mindepth 2 -maxdepth 2 -name test.hurl -print \ - | sed 's#/test.hurl$##' \ - | sort \ - | jq -R -s -c 'split("\n")[:-1]')" - else - examples="$(jq -nc \ - --arg telemetry "${{ steps.paths.outputs.telemetry }}" \ - --arg smtp "${{ steps.paths.outputs.smtp }}" \ - '[ - (if $telemetry == "true" then "examples/telemetry" else empty end), - (if $smtp == "true" then "examples/sending emails" else empty end) - ]')" - fi - echo "examples=$examples" >> "$GITHUB_OUTPUT" - if [[ "$examples" == '[]' ]]; then - echo 'No Hurl examples match these changes; Rust and Playwright checks still run.' >> "$GITHUB_STEP_SUMMARY" - else - echo "Selected Hurl examples: $examples" >> "$GITHUB_STEP_SUMMARY" - fi + run: scripts/select-hurl-examples.sh + env: + PATHS_OUTCOME: ${{ steps.paths.outcome }} + ALL_EXAMPLES: ${{ steps.paths.outputs.all_examples }} + MATCHED_EXAMPLES: ${{ steps.paths.outputs.changes }} - name: Restore Hurl archive id: hurl-cache if: steps.examples.outputs.examples != '[]' diff --git a/scripts/select-hurl-examples.sh b/scripts/select-hurl-examples.sh new file mode 100755 index 00000000..94b21c5b --- /dev/null +++ b/scripts/select-hurl-examples.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ "${PATHS_OUTCOME:-}" == success && "${ALL_EXAMPLES:-}" != true ]]; then + examples="$MATCHED_EXAMPLES" +else + # Tags, missing diff bases, and failed path filtering run every example. + examples="$(find examples -mindepth 2 -maxdepth 2 -name test.hurl -print \ + | sed 's#/test.hurl$##' | sort | jq -R -s -c 'split("\n")[:-1]')" +fi + +echo "examples=$examples" >> "$GITHUB_OUTPUT" +echo "Selected Hurl examples: $examples" >> "$GITHUB_STEP_SUMMARY" From 3736d4870f3338a7ce39f718cca52ce4641119e8 Mon Sep 17 00:00:00 2001 From: Ophir Lojkine Date: Thu, 8 Oct 2026 11:03:50 +0000 Subject: [PATCH 3/4] ci: map Hurl suites with distinct integration coverage --- .github/hurl-examples.yml | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/.github/hurl-examples.yml b/.github/hurl-examples.yml index 9b42762e..0a14ad8c 100644 --- a/.github/hurl-examples.yml +++ b/.github/hurl-examples.yml @@ -12,11 +12,92 @@ all_examples: - '.github/hurl-examples.yml' # Keys are example folders; add one glob per line to associate more files. +# Keep suites with distinctive integration coverage; describe it above each entry. + +# Trace propagation through nginx and actual OTLP export into Tempo. 'examples/telemetry': - 'src/telemetry.rs' + - 'src/app_config.rs' - 'src/main.rs' - 'src/webserver/http.rs' + - 'src/webserver/http_client.rs' - 'src/webserver/database/execute_queries.rs' + +# Mailpit checks delivered recipients, MIME parts, and attachment bytes. 'examples/sending emails': - 'src/app_config.rs' + - 'src/webserver/http_request_info.rs' - 'src/webserver/database/sqlpage_functions/functions/send_mail.rs' + - 'src/webserver/database/sqlpage_functions/functions/uploaded_file_name.rs' + - 'src/webserver/database/sqlpage_functions/functions/uploaded_file_path.rs' + - 'src/webserver/database/sqlpage_functions/functions/read_file_as_data_url.rs' + +# Real Keycloak discovery, login, callback cookies, and identity claims in SQL. +'examples/single sign on': + - 'src/app_config.rs' + - 'src/lib.rs' + - 'src/webserver/oidc.rs' + - 'src/webserver/http.rs' + - 'src/webserver/routing.rs' + - 'src/webserver/http_client.rs' + - 'src/webserver/http_request_info.rs' + - 'src/webserver/database/sqlpage_functions/functions/user_info*.rs' + - 'src/webserver/database/sqlpage_functions/functions/oidc_logout_url.rs' + +# A real proxy connects to SQLPage's Unix socket and rewrites pretty URLs. +'examples/nginx': + - 'src/app_config.rs' + - 'src/main.rs' + - 'src/webserver/http.rs' + - 'src/webserver/routing.rs' + +# Apache proxies a site prefix, including the missing trailing slash redirect. +'examples/web servers - apache': + - 'src/app_config.rs' + - 'src/webserver/http.rs' + - 'src/webserver/routing.rs' + +# Load SpatiaLite's native library and use its spatial functions on pooled SQLite. +'examples/make a geographic data application using sqlite extensions': + - 'src/app_config.rs' + - 'src/webserver/database/connect.rs' + +# Create a SQL page in PostgreSQL's sqlpage_files, then request it over HTTP. +'examples/SQLPage developer user interface': + - 'src/filesystem.rs' + - 'src/file_cache.rs' + - 'src/webserver/routing.rs' + - 'src/webserver/database/sqlpage_functions/functions/link.rs' + +# Posted arrays feed MySQL JSON_TABLE; native JSON builds the select options. +'examples/mysql json handling': + - 'src/webserver/http_request_info.rs' + - 'src/webserver/request_variables.rs' + - 'src/webserver/single_or_vec.rs' + - 'src/webserver/database/sql.rs' + - 'src/webserver/database/sql/**' + - 'src/webserver/database/execute_queries.rs' + - 'src/webserver/database/sql_to_json.rs' + - 'sqlpage/templates/form.handlebars' + +# A real cookie jar round-trips an encoded space and removes it from a subfolder. +'examples/read-and-set-http-cookies': + - 'src/render.rs' + - 'src/webserver/http_request_info.rs' + - 'src/webserver/database/sqlpage_functions/functions/cookie.rs' + +# Hash a new signup's password, authenticate it, and invalidate its login session. +'examples/user-authentication': + - 'src/render.rs' + - 'src/webserver/http_request_info.rs' + - 'src/webserver/database/sqlpage_functions/functions/hash_password.rs' + - 'src/webserver/database/sqlpage_functions/functions/random_string.rs' + - 'src/webserver/database/sqlpage_functions/functions/cookie.rs' + +# Authenticated multipart upload persists an image into a writable container mount. +'examples/image gallery with user uploads': + - 'src/app_config.rs' + - 'src/webserver/http_request_info.rs' + - 'src/webserver/database/sqlpage_functions/functions/persist_uploaded_file.rs' + - 'src/webserver/database/sqlpage_functions/functions/uploaded_file_mime_type.rs' + - 'src/webserver/database/sqlpage_functions/functions/random_string.rs' From 551da3a510290a4d8a6c5e107dce213e66229b5d Mon Sep 17 00:00:00 2001 From: Ophir Lojkine Date: Thu, 8 Oct 2026 11:09:12 +0000 Subject: [PATCH 4/4] ci: map complex templates to focused Hurl suites --- .github/hurl-examples.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/hurl-examples.yml b/.github/hurl-examples.yml index 0a14ad8c..54fd0298 100644 --- a/.github/hurl-examples.yml +++ b/.github/hurl-examples.yml @@ -23,7 +23,7 @@ all_examples: - 'src/webserver/http_client.rs' - 'src/webserver/database/execute_queries.rs' -# Mailpit checks delivered recipients, MIME parts, and attachment bytes. +# Mailpit checks delivered MIME parts; the form asserts delayed multipart encoding. 'examples/sending emails': - 'src/app_config.rs' - 'src/webserver/http_request_info.rs' @@ -31,6 +31,7 @@ all_examples: - 'src/webserver/database/sqlpage_functions/functions/uploaded_file_name.rs' - 'src/webserver/database/sqlpage_functions/functions/uploaded_file_path.rs' - 'src/webserver/database/sqlpage_functions/functions/read_file_as_data_url.rs' + - 'sqlpage/templates/form.handlebars' # Real Keycloak discovery, login, callback cookies, and identity claims in SQL. 'examples/single sign on': @@ -62,12 +63,13 @@ all_examples: - 'src/app_config.rs' - 'src/webserver/database/connect.rs' -# Create a SQL page in PostgreSQL's sqlpage_files, then request it over HTTP. +# Create a PostgreSQL-backed page, request it, and render dynamic rows in a table. 'examples/SQLPage developer user interface': - 'src/filesystem.rs' - 'src/file_cache.rs' - 'src/webserver/routing.rs' - 'src/webserver/database/sqlpage_functions/functions/link.rs' + - 'sqlpage/templates/table.handlebars' # Posted arrays feed MySQL JSON_TABLE; native JSON builds the select options. 'examples/mysql json handling': @@ -101,3 +103,9 @@ all_examples: - 'src/webserver/database/sqlpage_functions/functions/persist_uploaded_file.rs' - 'src/webserver/database/sqlpage_functions/functions/uploaded_file_mime_type.rs' - 'src/webserver/database/sqlpage_functions/functions/random_string.rs' + +# JSON menus with icon-only submenus and arrays of custom scripts/styles. +'examples/CRUD - Authentication': ['sqlpage/templates/shell.handlebars'] + +# Cards combine Markdown and remote chart/map/table embed markup. +'examples/cards-with-remote-content': ['sqlpage/templates/card.handlebars']