]> git.kaiwu.me - njs.git/commitdiff
CI: split CLI and nginx checks into parallel jobs
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 22 Oct 2026 23:27:06 +0000 (16:27 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Fri, 23 Oct 2026 23:13:30 +0000 (16:13 -0700)
Previously, check-pr runs all build configurations sequentially, so
an early failure prevents later configurations from being tested.

Split CLI checks into matrix configurations and nginx checks
into separate njs, QuickJS, and QuickJS-NG matrix jobs.  Disable
fail-fast and use fresh build directories without make clean.

Preserve the nginx module and SSL configure flags, sanitizer and
debug-memory settings, QuickJS-NG version, checkout action revision,
test commands, and failed-test retries.

Make engine selection explicit: njs jobs no longer auto-detect
QuickJS-NG, and the QuickJS CLI build uses an explicit library.

.github/scripts/nginx-ci.sh [new file with mode: 0644]
.github/workflows/check-pr.yml [deleted file]
.github/workflows/cli.yml [new file with mode: 0644]
.github/workflows/nginx.yml [new file with mode: 0644]

diff --git a/.github/scripts/nginx-ci.sh b/.github/scripts/nginx-ci.sh
new file mode 100644 (file)
index 0000000..52722bc
--- /dev/null
@@ -0,0 +1,208 @@
+#!/bin/bash
+
+set -euo pipefail
+
+export DEB_BUILD_MAINT_OPTIONS=hardening=+all
+export DEB_CFLAGS_MAINT_APPEND=-fPIC
+export DEB_LDFLAGS_MAINT_APPEND=-Wl,--as-needed
+
+prepare() {
+    sudo apt-get update
+    sudo apt-get install -y libssl-dev zlib1g-dev libpcre2-dev libxslt1-dev \
+        libgeoip-dev libgd-dev libxml2-dev libedit-dev libperl-dev \
+        libtest-harness-perl libgd-perl expect meson ninja-build
+
+    local cc_opt ld_opt
+    cc_opt=$(dpkg-buildflags --get CFLAGS)
+    ld_opt=$(dpkg-buildflags --get LDFLAGS)
+
+    git clone https://github.com/nginx/nginx nginx-source
+    git clone https://github.com/nginx/nginx-tests
+
+    case "$CI_ENGINE" in
+        njs) ;;
+        quickjs)
+            git clone https://github.com/bellard/quickjs
+            CFLAGS="$cc_opt" LDFLAGS="$ld_opt" \
+                make -C quickjs -j"$(nproc)" libquickjs.a
+            ;;
+        quickjs-ng)
+            git clone --branch v0.16.2 --depth=1 \
+                https://github.com/quickjs-ng/quickjs quickjs-ng
+            CFLAGS="$cc_opt -fPIC" LDFLAGS="$ld_opt" \
+                meson setup quickjs-ng/build quickjs-ng \
+                    --prefix="$HOME/.local" --libdir=lib -Ddefault_library=static
+            meson compile -C quickjs-ng/build
+            meson install -C quickjs-ng/build
+            ;;
+        *) echo "Unknown engine: $CI_ENGINE" >&2; exit 1 ;;
+    esac
+
+    if [ "$CI_ASAN" = yes ]; then
+        echo 'leak:ngx_event_process_init' > lsan_suppressions.txt
+    fi
+}
+
+asan_environment() {
+    case "$CI_ASAN" in
+        yes)
+            export ASAN_OPTIONS=detect_odr_violation=0:report_globals=0
+            case "$CI_ASAN_FAST_UNWIND" in
+                yes) ;;
+                no) ASAN_OPTIONS+=:fast_unwind_on_malloc=0 ;;
+                *)
+                    echo "Unknown ASan fast-unwind configuration: $CI_ASAN_FAST_UNWIND" >&2
+                    exit 1
+                    ;;
+            esac
+            export LSAN_OPTIONS="suppressions=$PWD/lsan_suppressions.txt"
+            ;;
+        no) ;;
+        *) echo "Unknown ASan configuration: $CI_ASAN" >&2; exit 1 ;;
+    esac
+}
+
+test_engine() {
+    local engine=$1
+
+    case " $CI_TEST_ENGINES " in
+        *" $engine "*) ;;
+        *) echo "Test engine is not configured: $engine" >&2; exit 1 ;;
+    esac
+
+    asan_environment
+    export TEST_NGINX_BINARY="$PWD/nginx-source/objs/nginx"
+    export TEST_NGINX_VERBOSE=1
+    if [ "$CI_LINKAGE" = dynamic ]; then
+        TEST_NGINX_GLOBALS="load_module $PWD/nginx-source/objs/ngx_http_js_module.so;"
+        TEST_NGINX_GLOBALS+=" load_module $PWD/nginx-source/objs/ngx_stream_js_module.so;"
+        export TEST_NGINX_GLOBALS
+    fi
+
+    case "$engine" in
+        njs)
+            unset TEST_NGINX_GLOBALS_HTTP TEST_NGINX_GLOBALS_STREAM
+            ;;
+        qjs)
+            export TEST_NGINX_GLOBALS_HTTP='js_engine qjs;'
+            export TEST_NGINX_GLOBALS_STREAM='js_engine qjs;'
+            ;;
+        *) echo "Unknown test engine: $engine" >&2; exit 1 ;;
+    esac
+
+    ulimit -c unlimited
+    export TMPDIR
+    TMPDIR=$(mktemp -d)
+    prove -v -j"$(nproc)" -Inginx-tests/lib --state=save nginx/t . \
+        || prove -v -Inginx-tests/lib --state=failed
+}
+
+case "${1:-}" in
+    prepare) prepare; exit ;;
+    build) ;;
+    test) test_engine "${2:?Missing test engine}"; exit ;;
+    *) echo "Usage: $0 prepare|build|test <engine>" >&2; exit 1 ;;
+esac
+
+cc_opt=$(dpkg-buildflags --get CFLAGS)
+ld_opt=$(dpkg-buildflags --get LDFLAGS)
+
+case "$CI_ENGINE" in
+    njs)
+        export NJS_QUICKJS=NO
+        ;;
+    quickjs)
+        cc_opt+=" -I$PWD/quickjs"
+        ld_opt+=" -L$PWD/quickjs"
+        ;;
+    quickjs-ng)
+        export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig"
+        ;;
+    *) echo "Unknown engine: $CI_ENGINE" >&2; exit 1 ;;
+esac
+
+options=(
+    --prefix=/tmp
+    --with-http_realip_module
+    --with-http_addition_module
+    --with-http_sub_module
+    --with-http_dav_module
+    --with-http_flv_module
+    --with-http_mp4_module
+    --with-http_gunzip_module
+    --with-http_gzip_static_module
+    --with-http_random_index_module
+    --with-http_secure_link_module
+    --with-http_stub_status_module
+    --with-mail
+    --with-select_module
+    --with-poll_module
+    --with-http_auth_request_module
+    --with-http_v2_module
+    --with-http_slice_module
+    --with-stream
+    --with-stream_realip_module
+    --with-threads
+    --with-cpp_test_module
+    --with-compat
+    --with-http_degradation_module
+    --with-http_xslt_module
+    --with-http_image_filter_module
+    --with-http_perl_module
+    --with-http_geoip_module
+    --with-stream_geoip_module
+)
+
+case "$CI_SSL" in
+    yes)
+        options+=(--with-http_ssl_module --with-mail_ssl_module
+            --with-stream_ssl_module --with-stream_ssl_preread_module)
+        ;;
+    no) export NJS_OPENSSL=NO ;;
+    *) echo "Unknown SSL configuration: $CI_SSL" >&2; exit 1 ;;
+esac
+
+case "$CI_LINKAGE" in
+    static) options+=(--add-module=../nginx) ;;
+    dynamic) options+=(--add-dynamic-module=../nginx) ;;
+    *) echo "Unknown module linkage: $CI_LINKAGE" >&2; exit 1 ;;
+esac
+
+case "$CI_DEBUG" in
+    yes) options+=(--with-debug) ;;
+    no) ;;
+    *) echo "Unknown debug configuration: $CI_DEBUG" >&2; exit 1 ;;
+esac
+
+case "$CI_DEBUG_MEMORY" in
+    yes)
+        cc_opt+=" -DNJS_DEBUG_MEMORY -DNGX_DEBUG_PALLOC -DNGX_DEBUG_MALLOC"
+        ;;
+    no) ;;
+    *) echo "Unknown debug-memory configuration: $CI_DEBUG_MEMORY" >&2; exit 1 ;;
+esac
+
+case "$CI_ASAN" in
+    yes)
+        cc_opt+=" -fsanitize=address"
+        ld_opt+=" -fsanitize=address"
+        ;;
+    no) ;;
+    *) echo "Unknown ASan configuration: $CI_ASAN" >&2; exit 1 ;;
+esac
+
+asan_environment
+
+(
+    cd nginx-source
+    auto/configure "${options[@]}" --with-cc-opt="$cc_opt" \
+        --with-ld-opt="$ld_opt" || { cat objs/autoconf.err; exit 1; }
+    make -j"$(nproc)" modules
+    make -j"$(nproc)"
+)
+
+# Do not silently lose QuickJS coverage if library detection fails.
+if [ "$CI_ENGINE" != njs ]; then
+    grep -q '^#define NJS_HAVE_QUICKJS  1' \
+        nginx-source/objs/njs/njs_auto_config.h
+fi
diff --git a/.github/workflows/check-pr.yml b/.github/workflows/check-pr.yml
deleted file mode 100644 (file)
index 9490645..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-name: check-pr
-
-on:
-  pull_request:
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.ref }}
-  cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
-
-jobs:
-  build:
-    runs-on: [ ubuntu-24.04 ]
-    steps:
-      - name: checkout v4
-        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
-
-      - name: Set the defaults and set up environment
-        run: |
-          NGINX_BASE="auto/configure --prefix=/tmp --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-mail --with-select_module --with-poll_module --with-http_auth_request_module --with-http_v2_module --with-http_slice_module --with-stream --with-stream_realip_module --with-threads --with-cpp_test_module --with-compat --with-http_degradation_module --with-http_xslt_module --with-http_image_filter_module --with-http_perl_module --with-http_geoip_module --with-stream_geoip_module"
-          SSL_MODULES="--with-http_ssl_module --with-mail_ssl_module --with-stream_ssl_module --with-stream_ssl_preread_module"
-          echo NGINX_CONFIGURE_CMD="$NGINX_BASE $SSL_MODULES" >> $GITHUB_ENV
-          echo NGINX_CONFIGURE_CMD_NO_SSL="$NGINX_BASE" >> $GITHUB_ENV
-          export DEB_BUILD_MAINT_OPTIONS="hardening=+all"
-          export DEB_CFLAGS_MAINT_APPEND="-fPIC"
-          export DEB_LDFLAGS_MAINT_APPEND=""-Wl,--as-needed""
-          echo CC_OPT=$(dpkg-buildflags --get CFLAGS) >> $GITHUB_ENV
-          echo LD_OPT=$(dpkg-buildflags --get LDFLAGS) >> $GITHUB_ENV
-          echo MAKE_UTILITY=make >> $GITHUB_ENV
-
-      - name: Install build dependencies
-        run: |
-          sudo apt-get update
-          sudo apt-get install \
-          libssl-dev zlib1g-dev libpcre2-dev libxslt1-dev libgeoip-dev \
-          libgd-dev libxml2-dev libedit-dev libperl-dev libtest-harness-perl \
-          libgd-perl libgeoip-dev expect meson ninja-build
-
-      - name: Install x86 build dependencies
-        run: |
-          sudo dpkg --add-architecture i386
-          sudo apt-get update
-          sudo apt-get install -y gcc-multilib libc6:i386 libssl-dev:i386 libpcre2-dev:i386 zlib1g-dev:i386 libxml2-dev:i386
-
-      - name: Check out nginx
-        run: |
-          git clone https://github.com/nginx/nginx nginx-source
-
-      - name: Check out nginx tests
-        run: |
-          git clone https://github.com/nginx/nginx-tests
-
-      - name: Check out and build quickjs
-        run: |
-          git clone https://github.com/bellard/quickjs
-          cd quickjs
-          CFLAGS=$CC_OPT LDFLAGS=$LD_OPT $MAKE_UTILITY -j$(nproc) libquickjs.a
-
-      - name: Check out and build quickjs-ng
-        run: |
-          git clone https://github.com/quickjs-ng/quickjs quickjs-ng
-          cd quickjs-ng
-          git checkout v0.16.2
-          CFLAGS="$CC_OPT -fPIC" LDFLAGS=$LD_OPT meson setup build --prefix=$HOME/.local --libdir=lib -Ddefault_library=static
-          meson compile -C build
-          meson install -C build
-          echo "PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH" >> $GITHUB_ENV
-
-      - name: Configure and make njs with UBSan
-        run: |
-          ./configure \
-                    --cc-opt="$CC_OPT -fsanitize=undefined" \
-                    --ld-opt="$LD_OPT -fsanitize=undefined" \
-          || cat build/autoconf.err
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs with UBSan
-        run: |
-          UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 $MAKE_UTILITY test
-          $MAKE_UTILITY clean
-
-      - name: Configure and make njs, 32-bit
-        run: |
-          ./configure \
-                    --cc-opt="$CC_OPT -m32" \
-                    --ld-opt="$LD_OPT" \
-          || cat build/autoconf.err
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs, 32-bit
-        run: |
-          $MAKE_UTILITY test
-          $MAKE_UTILITY clean
-
-      - name: Configure and make njs with quickjs
-        run: |
-          ./configure \
-                    --with-quickjs \
-                    --debug=YES \
-                    --debug-memory=YES \
-                    --address-sanitizer=YES \
-                    --cc-opt="$CC_OPT -Iquickjs" \
-                    --ld-opt="$LD_OPT -Lquickjs" \
-          || cat build/autoconf.err
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs with quickjs
-        run: |
-          $MAKE_UTILITY test
-          $MAKE_UTILITY clean
-
-      - name: Configure and make njs with ASan, no debug memory
-        run: |
-          ./configure \
-                    --debug=YES \
-                    --address-sanitizer=YES \
-                    --cc-opt="$CC_OPT" \
-                    --ld-opt="$LD_OPT" \
-          || cat build/autoconf.err
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs with ASan, no debug memory
-        run: |
-          $MAKE_UTILITY test
-          $MAKE_UTILITY clean
-
-      - name: Configure and make njs with quickjs-ng
-        run: |
-          ./configure \
-                    --with-quickjs \
-                    --cc-opt="$CC_OPT" \
-                    --ld-opt="$LD_OPT" \
-          || cat build/autoconf.err
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs with quickjs-ng
-        run: |
-          $MAKE_UTILITY test
-          $MAKE_UTILITY clean
-
-      - name: Configure and build nginx and njs modules
-        run: |
-          cd nginx-source
-          $NGINX_CONFIGURE_CMD --with-cc-opt="$CC_OPT" --with-ld-opt="$LD_OPT" --add-dynamic-module=../nginx || cat objs/autoconf.err
-          $MAKE_UTILITY -j$(nproc) modules
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_GLOBALS: "load_module ${{ github.workspace }}/nginx-source/objs/ngx_http_js_module.so; load_module ${{ github.workspace }}/nginx-source/objs/ngx_stream_js_module.so;"
-          TEST_NGINX_VERBOSE: 1
-
-      - name: Configure and build nginx and njs modules, no SSL, static modules
-        run: |
-          cd nginx-source
-          NJS_OPENSSL=NO $NGINX_CONFIGURE_CMD_NO_SSL --with-cc-opt="$CC_OPT" --with-ld-opt="$LD_OPT" --add-module=../nginx || cat objs/autoconf.err
-          $MAKE_UTILITY -j$(nproc) modules
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs modules, no SSL, static modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_VERBOSE: 1
-
-      - name: Create LSAN suppression file
-        run: |
-          cat << EOF > lsan_suppressions.txt
-          leak:ngx_event_process_init
-          EOF
-
-      - name: Configure and build nginx and njs modules with quickjs, asan, static modules
-        run: |
-          cd nginx-source
-          $MAKE_UTILITY clean
-          $NGINX_CONFIGURE_CMD --with-cc-opt="$CC_OPT -I${{ github.workspace }}/quickjs -fsanitize=address -DNJS_DEBUG_MEMORY -DNGX_DEBUG_PALLOC -DNGX_DEBUG_MALLOC" --with-ld-opt="$LD_OPT -L${{ github.workspace }}/quickjs -fsanitize=address" --add-module=../nginx || cat objs/autoconf.err
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs modules, static modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_VERBOSE: 1
-          ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0"
-          LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"
-
-      - name: Test njs modules (js_engine qjs), static modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_GLOBALS_HTTP: "js_engine qjs;"
-          TEST_NGINX_GLOBALS_STREAM: "js_engine qjs;"
-          TEST_NGINX_VERBOSE: 1
-          ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0"
-          LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"
-
-      - name: Configure and build nginx and njs modules with quickjs, asan, dynamic modules
-        run: |
-          cd nginx-source
-          $NGINX_CONFIGURE_CMD --with-debug --with-cc-opt="$CC_OPT -I${{ github.workspace }}/quickjs -fsanitize=address -DNJS_DEBUG_MEMORY -DNGX_DEBUG_PALLOC -DNGX_DEBUG_MALLOC" --with-ld-opt="$LD_OPT -L${{ github.workspace }}/quickjs -fsanitize=address" --add-dynamic-module=../nginx || cat objs/autoconf.err
-          $MAKE_UTILITY -j$(nproc) modules
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs modules, dynamic modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_GLOBALS: "load_module ${{ github.workspace }}/nginx-source/objs/ngx_http_js_module.so; load_module ${{ github.workspace }}/nginx-source/objs/ngx_stream_js_module.so;"
-          TEST_NGINX_VERBOSE: 1
-          ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0:fast_unwind_on_malloc=0"
-          LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"
-
-      - name: Test njs modules (js_engine qjs), dynamic modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_GLOBALS: "load_module ${{ github.workspace }}/nginx-source/objs/ngx_stream_js_module.so; load_module ${{ github.workspace }}/nginx-source/objs/ngx_http_js_module.so;"
-          TEST_NGINX_GLOBALS_HTTP: "js_engine qjs;"
-          TEST_NGINX_GLOBALS_STREAM: "js_engine qjs;"
-          TEST_NGINX_VERBOSE: 1
-          ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0:fast_unwind_on_malloc=0"
-          LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"
-
-      - name: Configure and build nginx and njs modules with quickjs-ng, asan, static modules
-        run: |
-          cd nginx-source
-          $NGINX_CONFIGURE_CMD --with-cc-opt="$CC_OPT -fsanitize=address -DNJS_DEBUG_MEMORY -DNGX_DEBUG_PALLOC -DNGX_DEBUG_MALLOC" --with-ld-opt="$LD_OPT -fsanitize=address" --add-module=../nginx || cat objs/autoconf.err
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs modules, quickjs-ng, static modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_VERBOSE: 1
-          ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0"
-          LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"
-
-      - name: Test njs modules (js_engine qjs), quickjs-ng, static modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_GLOBALS_HTTP: "js_engine qjs;"
-          TEST_NGINX_GLOBALS_STREAM: "js_engine qjs;"
-          TEST_NGINX_VERBOSE: 1
-          ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0"
-          LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"
-
-      - name: Configure and build nginx and njs modules with quickjs-ng, asan, dynamic modules
-        run: |
-          cd nginx-source
-          $NGINX_CONFIGURE_CMD --with-debug --with-cc-opt="$CC_OPT -fsanitize=address -DNJS_DEBUG_MEMORY -DNGX_DEBUG_PALLOC -DNGX_DEBUG_MALLOC" --with-ld-opt="$LD_OPT -fsanitize=address" --add-dynamic-module=../nginx || cat objs/autoconf.err
-          $MAKE_UTILITY -j$(nproc) modules
-          $MAKE_UTILITY -j$(nproc)
-
-      - name: Test njs modules, quickjs-ng, dynamic modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_GLOBALS: "load_module ${{ github.workspace }}/nginx-source/objs/ngx_stream_js_module.so; load_module ${{ github.workspace }}/nginx-source/objs/ngx_http_js_module.so;"
-          TEST_NGINX_VERBOSE: 1
-          ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0:fast_unwind_on_malloc=0"
-          LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"
-
-      - name: Test njs modules (js_engine qjs), quickjs-ng, dynamic modules
-        run: |
-          ulimit -c unlimited
-          prove -v -j$(nproc) -Inginx-tests/lib --state=save nginx/t . || prove -v -Inginx-tests/lib --state=failed
-        env:
-          TEST_NGINX_BINARY: "${{ github.workspace }}/nginx-source/objs/nginx"
-          TEST_NGINX_GLOBALS: "load_module ${{ github.workspace }}/nginx-source/objs/ngx_stream_js_module.so; load_module ${{ github.workspace }}/nginx-source/objs/ngx_http_js_module.so;"
-          TEST_NGINX_GLOBALS_HTTP: "js_engine qjs;"
-          TEST_NGINX_GLOBALS_STREAM: "js_engine qjs;"
-          TEST_NGINX_VERBOSE: 1
-          ASAN_OPTIONS: "detect_odr_violation=0:report_globals=0:fast_unwind_on_malloc=0"
-          LSAN_OPTIONS: "suppressions=${{ github.workspace }}/lsan_suppressions.txt"
diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml
new file mode 100644 (file)
index 0000000..bd2ff9f
--- /dev/null
@@ -0,0 +1,130 @@
+name: cli
+
+on:
+  pull_request:
+  workflow_dispatch:
+
+permissions:
+  contents: read
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
+
+jobs:
+  cli:
+    name: ${{ matrix.name }}
+    runs-on: ubuntu-24.04
+    timeout-minutes: 30
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - name: njs UBSan
+            engine: njs
+            mode: ubsan
+          - name: njs 32-bit
+            engine: njs
+            mode: 32-bit
+          - name: njs ASan
+            engine: njs
+            mode: asan
+          - name: QuickJS ASan debug-memory
+            engine: quickjs
+            mode: asan-debug-memory
+          - name: QuickJS-NG
+            engine: quickjs-ng
+            mode: normal
+          - name: QuickJS-NG UBSan
+            engine: quickjs-ng
+            mode: ubsan
+          - name: QuickJS-NG ASan
+            engine: quickjs-ng
+            mode: asan
+    env:
+      CI_ENGINE: ${{ matrix.engine }}
+      CI_MODE: ${{ matrix.mode }}
+      DEB_BUILD_MAINT_OPTIONS: hardening=+all
+      DEB_CFLAGS_MAINT_APPEND: -fPIC
+      DEB_LDFLAGS_MAINT_APPEND: -Wl,--as-needed
+
+    steps:
+      - name: Checkout njs
+        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+        with:
+          persist-credentials: false
+
+      - name: Install build dependencies
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y libssl-dev zlib1g-dev libpcre2-dev \
+              libxml2-dev libedit-dev expect meson ninja-build
+
+      - name: Install 32-bit build dependencies
+        if: matrix.mode == '32-bit'
+        run: |
+          sudo dpkg --add-architecture i386
+          sudo apt-get update
+          sudo apt-get install -y gcc-multilib libc6:i386 libssl-dev:i386 \
+              libpcre2-dev:i386 zlib1g-dev:i386 libxml2-dev:i386
+
+      - name: Build QuickJS
+        if: matrix.engine == 'quickjs'
+        run: |
+          git clone https://github.com/bellard/quickjs
+          CFLAGS="$(dpkg-buildflags --get CFLAGS)" \
+          LDFLAGS="$(dpkg-buildflags --get LDFLAGS)" \
+              make -C quickjs -j"$(nproc)" libquickjs.a
+
+      - name: Build QuickJS-NG
+        if: matrix.engine == 'quickjs-ng'
+        run: |
+          git clone --branch v0.16.2 --depth=1 \
+              https://github.com/quickjs-ng/quickjs quickjs-ng
+          CFLAGS="$(dpkg-buildflags --get CFLAGS) -fPIC" \
+          LDFLAGS="$(dpkg-buildflags --get LDFLAGS)" \
+              meson setup quickjs-ng/build quickjs-ng \
+                  --prefix="$HOME/.local" --libdir=lib -Ddefault_library=static
+          meson compile -C quickjs-ng/build
+          meson install -C quickjs-ng/build
+          echo "PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig" >> "$GITHUB_ENV"
+
+      - name: Configure and build CLI
+        run: |
+          cc_opt=$(dpkg-buildflags --get CFLAGS)
+          ld_opt=$(dpkg-buildflags --get LDFLAGS)
+          options=()
+
+          case "$CI_ENGINE" in
+              njs) options+=(--no-quickjs) ;;
+              quickjs)
+                  options+=(--with-quickjs --quickjs-inc="$PWD/quickjs"
+                      --quickjs-lib="$PWD/quickjs/libquickjs.a -lm -ldl -lpthread")
+                  ;;
+              quickjs-ng) options+=(--with-quickjs) ;;
+          esac
+
+          case "$CI_MODE" in
+              ubsan)
+                  cc_opt+=" -fsanitize=undefined"
+                  ld_opt+=" -fsanitize=undefined"
+                  ;;
+              32-bit)
+                  cc_opt+=" -m32"
+                  ld_opt+=" -m32"
+                  ;;
+              asan) options+=(--debug=YES --address-sanitizer=YES) ;;
+              asan-debug-memory)
+                  options+=(--debug=YES --debug-memory=YES
+                      --address-sanitizer=YES)
+                  ;;
+          esac
+
+          ./configure "${options[@]}" --cc-opt="$cc_opt" --ld-opt="$ld_opt" \
+              || { cat build/autoconf.err; exit 1; }
+          make -j"$(nproc)" njs
+
+      - name: Test CLI
+        run: make test
+        env:
+          UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
diff --git a/.github/workflows/nginx.yml b/.github/workflows/nginx.yml
new file mode 100644 (file)
index 0000000..42b9057
--- /dev/null
@@ -0,0 +1,141 @@
+name: nginx
+
+on:
+  pull_request:
+  workflow_dispatch:
+
+permissions:
+  contents: read
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
+
+jobs:
+  njs:
+    name: njs ${{ matrix.linkage }} SSL=${{ matrix.ssl }}
+    runs-on: ubuntu-24.04
+    timeout-minutes: 45
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - linkage: dynamic
+            ssl: 'yes'
+          - linkage: static
+            ssl: 'no'
+    env:
+      CI_ENGINE: njs
+      CI_LINKAGE: ${{ matrix.linkage }}
+      CI_SSL: ${{ matrix.ssl }}
+      CI_ASAN: 'no'
+      CI_DEBUG: 'no'
+      CI_DEBUG_MEMORY: 'no'
+      CI_TEST_ENGINES: njs
+    steps:
+      - name: Checkout njs
+        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+        with:
+          persist-credentials: false
+      - name: Prepare dependencies
+        run: bash .github/scripts/nginx-ci.sh prepare
+      - name: Build nginx modules
+        run: bash .github/scripts/nginx-ci.sh build
+      - name: Test nginx modules (njs)
+        if: contains(env.CI_TEST_ENGINES, 'njs')
+        run: bash .github/scripts/nginx-ci.sh test njs
+      - name: Test nginx modules (qjs)
+        if: contains(env.CI_TEST_ENGINES, 'qjs')
+        run: bash .github/scripts/nginx-ci.sh test qjs
+
+  quickjs:
+    name: QuickJS ${{ matrix.linkage }} ASan
+    runs-on: ubuntu-24.04
+    timeout-minutes: 45
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - linkage: static
+            debug: 'no'
+            asan-fast-unwind: 'yes'
+          - linkage: dynamic
+            debug: 'yes'
+            asan-fast-unwind: 'no'
+    env:
+      CI_ENGINE: quickjs
+      CI_LINKAGE: ${{ matrix.linkage }}
+      CI_SSL: 'yes'
+      CI_ASAN: 'yes'
+      CI_ASAN_FAST_UNWIND: ${{ matrix.asan-fast-unwind }}
+      CI_DEBUG: ${{ matrix.debug }}
+      CI_DEBUG_MEMORY: 'yes'
+      CI_TEST_ENGINES: njs qjs
+    steps:
+      - name: Checkout njs
+        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+        with:
+          persist-credentials: false
+      - name: Prepare dependencies
+        run: bash .github/scripts/nginx-ci.sh prepare
+      - name: Build nginx modules
+        run: bash .github/scripts/nginx-ci.sh build
+      - name: Test nginx modules (njs)
+        if: contains(env.CI_TEST_ENGINES, 'njs')
+        run: bash .github/scripts/nginx-ci.sh test njs
+      - name: Test nginx modules (qjs)
+        if: contains(env.CI_TEST_ENGINES, 'qjs')
+        run: bash .github/scripts/nginx-ci.sh test qjs
+
+  quickjs-ng:
+    name: QuickJS-NG ${{ matrix.name }}
+    runs-on: ubuntu-24.04
+    timeout-minutes: 45
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - name: static ASan
+            linkage: static
+            ssl: 'yes'
+            asan: 'yes'
+            debug: 'no'
+            debug-memory: 'yes'
+            asan-fast-unwind: 'yes'
+          - name: dynamic ASan
+            linkage: dynamic
+            ssl: 'yes'
+            asan: 'yes'
+            debug: 'yes'
+            debug-memory: 'yes'
+            asan-fast-unwind: 'no'
+          - name: static SSL=no
+            linkage: static
+            ssl: 'no'
+            asan: 'no'
+            debug: 'no'
+            debug-memory: 'no'
+    env:
+      CI_ENGINE: quickjs-ng
+      CI_LINKAGE: ${{ matrix.linkage }}
+      CI_SSL: ${{ matrix.ssl }}
+      CI_ASAN: ${{ matrix.asan }}
+      CI_ASAN_FAST_UNWIND: ${{ matrix.asan-fast-unwind }}
+      CI_DEBUG: ${{ matrix.debug }}
+      CI_DEBUG_MEMORY: ${{ matrix.debug-memory }}
+      CI_TEST_ENGINES: njs qjs
+    steps:
+      - name: Checkout njs
+        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+        with:
+          persist-credentials: false
+      - name: Prepare dependencies
+        run: bash .github/scripts/nginx-ci.sh prepare
+      - name: Build nginx modules
+        run: bash .github/scripts/nginx-ci.sh build
+      - name: Test nginx modules (njs)
+        if: contains(env.CI_TEST_ENGINES, 'njs')
+        run: bash .github/scripts/nginx-ci.sh test njs
+      - name: Test nginx modules (qjs)
+        if: contains(env.CI_TEST_ENGINES, 'qjs')
+        run: bash .github/scripts/nginx-ci.sh test qjs