From 382fd7bbab37dbdead1a42f7dccd3dc4059c402e Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 17 Nov 2023 14:24:10 -0500 Subject: [PATCH 1/6] ci: make sure the ports cache key includes extconf because extconf contains the recipe by which libxml2/libxslt are built --- .github/workflows/ci.yml | 14 +++++++------- .github/workflows/downstream.yml | 2 +- .github/workflows/upstream.yml | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df1b15d7fed..61798b3a75e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,7 +110,7 @@ jobs: if: matrix.sys == 'disable' with: path: ports - key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - run: bundle install --local || bundle install - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries - run: bundle exec rake test @@ -141,7 +141,7 @@ jobs: if: matrix.sys == 'disable' with: path: ports - key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - run: bundle install --local || bundle install - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries - run: bundle exec rake test:valgrind @@ -202,7 +202,7 @@ jobs: if: matrix.sys == 'disable' with: path: ports - key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - run: bundle install --local || bundle install - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries - run: bundle exec rake test @@ -227,7 +227,7 @@ jobs: if: matrix.sys == 'disable' with: path: ports - key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - run: bundle install --local || bundle install - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries - run: bundle exec rake test:valgrind @@ -253,7 +253,7 @@ jobs: if: matrix.sys == 'disable' with: path: ports - key: ports-macos-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-macos-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries - run: bundle exec rake test @@ -283,7 +283,7 @@ jobs: if: matrix.sys == 'disable' with: path: ports - key: ports-windows-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-windows-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries - run: bundle exec rake test @@ -378,7 +378,7 @@ jobs: if: matrix.sys == 'disable' with: path: ports - key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - run: bundle install --local || bundle install - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries - run: bundle exec rake test:memcheck diff --git a/.github/workflows/downstream.yml b/.github/workflows/downstream.yml index 90d8349459b..0ae0a88acb2 100644 --- a/.github/workflows/downstream.yml +++ b/.github/workflows/downstream.yml @@ -78,7 +78,7 @@ jobs: - uses: actions/cache@v3 with: path: ports - key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-ubuntu-${{matrix.ruby}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - if: matrix.precommand run: ${{matrix.precommand}} - run: gem install bundler -v ">= 2.3.22" # for "add --path" diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index b9d65333e14..197af4df0df 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -118,7 +118,7 @@ jobs: if: matrix.sys == 'disable' with: path: ports - key: ports-${{matrix.plat}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-${{matrix.plat}}-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries - run: bundle exec rake test @@ -142,7 +142,7 @@ jobs: if: matrix.sys == 'disable' with: path: ports - key: ports-ubuntu-head-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-ubuntu-head-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - run: bundle exec rake compile -- --${{matrix.sys}}-system-libraries - run: bundle exec rake test:valgrind - run: bundle exec rake test:memcheck @@ -172,7 +172,7 @@ jobs: - uses: actions/cache@v3 with: path: ports - key: ports-ubuntu-3.2-${{hashFiles('dependencies.yml', 'patches/**/*.patch')}} + key: ports-ubuntu-3.2-${{hashFiles('dependencies.yml', 'patches/**/*.patch', 'ext/nokogiri/extconf.rb')}} - name: Update html5lib-tests run: | cd test/html5lib-tests From ba4f31bdd136109c0db26a64ba1494d289a3a9b5 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 16 Nov 2023 22:52:28 -0500 Subject: [PATCH 2/6] dep: update libxml to 2.12.0 and libxslt to 1.1.39 though note that libxslt was also previously updated to 1.1.39 on the v1.15.x branch. - https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.12.0 - https://gitlab.gnome.org/GNOME/libxslt/-/releases/v1.1.39 --- dependencies.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dependencies.yml b/dependencies.yml index 0aa95bb151a..40a78dfefc9 100644 --- a/dependencies.yml +++ b/dependencies.yml @@ -1,12 +1,12 @@ libxml2: - version: "2.11.5" - sha256: "3727b078c360ec69fa869de14bd6f75d7ee8d36987b071e6928d4720a28df3a6" - # sha-256 hash provided in https://download.gnome.org/sources/libxml2/2.11/libxml2-2.11.5.sha256sum + version: "2.12.0" + sha256: "431521c8e19ca396af4fa97743b5a6bfcccddbba90e16426a15e5374cd64fe0d" + # sha-256 hash provided in https://download.gnome.org/sources/libxml2/2.12/libxml2-2.12.0.sha256sum libxslt: - version: "1.1.38" - sha256: "1f32450425819a09acaff2ab7a5a7f8a2ec7956e505d7beeb45e843d0e1ecab1" - # sha-256 hash provided in https://download.gnome.org/sources/libxslt/1.1/libxslt-1.1.38.sha256sum + version: "1.1.39" + sha256: "2a20ad621148339b0759c4d4e96719362dee64c9a096dbba625ba053846349f0" + # sha-256 hash provided in https://download.gnome.org/sources/libxslt/1.1/libxslt-1.1.39.sha256sum zlib: version: "1.3" From f3516ae734be8d3b65cfc35527ac60b725acc31f Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Tue, 24 Oct 2023 08:39:53 -0400 Subject: [PATCH 3/6] dev: handle libxml 2.12's use of const for xmlError pointers see https://gitlab.gnome.org/GNOME/libxml2/-/commit/45470611b047db78106dcb2fdbd4164163c15ab7 and other upstream commits --- ext/nokogiri/html4_sax_push_parser.c | 2 +- ext/nokogiri/nokogiri.h | 9 ++++++--- ext/nokogiri/test_global_handlers.c | 2 +- ext/nokogiri/xml_document.c | 6 +++--- ext/nokogiri/xml_node.c | 2 +- ext/nokogiri/xml_reader.c | 2 +- ext/nokogiri/xml_relax_ng.c | 2 +- ext/nokogiri/xml_sax_push_parser.c | 2 +- ext/nokogiri/xml_schema.c | 2 +- ext/nokogiri/xml_syntax_error.c | 6 +++--- 10 files changed, 19 insertions(+), 16 deletions(-) diff --git a/ext/nokogiri/html4_sax_push_parser.c b/ext/nokogiri/html4_sax_push_parser.c index 569f76c5859..6955c0dcdb9 100644 --- a/ext/nokogiri/html4_sax_push_parser.c +++ b/ext/nokogiri/html4_sax_push_parser.c @@ -32,7 +32,7 @@ native_write(VALUE self, VALUE _chunk, VALUE _last_chunk) if ((status != 0) && !(ctx->options & XML_PARSE_RECOVER)) { // TODO: there appear to be no tests for this block - xmlErrorPtr e = xmlCtxtGetLastError(ctx); + xmlErrorConstPtr e = xmlCtxtGetLastError(ctx); Nokogiri_error_raise(NULL, e); } diff --git a/ext/nokogiri/nokogiri.h b/ext/nokogiri/nokogiri.h index ffc1749b91d..b8d6e18ba52 100644 --- a/ext/nokogiri/nokogiri.h +++ b/ext/nokogiri/nokogiri.h @@ -66,6 +66,9 @@ xmlNodePtr xmlLastElementChild(xmlNodePtr parent); #define XMLNS_PREFIX "xmlns" #define XMLNS_PREFIX_LEN 6 /* including either colon or \0 */ +#ifndef xmlErrorConstPtr +# define xmlErrorConstPtr const xmlError * +#endif #include #include @@ -227,9 +230,9 @@ void Nokogiri_structured_error_func_save(libxmlStructuredErrorHandlerState *hand void Nokogiri_structured_error_func_save_and_set(libxmlStructuredErrorHandlerState *handler_state, void *user_data, xmlStructuredErrorFunc handler); void Nokogiri_structured_error_func_restore(libxmlStructuredErrorHandlerState *handler_state); -VALUE Nokogiri_wrap_xml_syntax_error(xmlErrorPtr error); -void Nokogiri_error_array_pusher(void *ctx, xmlErrorPtr error); -NORETURN_DECL void Nokogiri_error_raise(void *ctx, xmlErrorPtr error); +VALUE Nokogiri_wrap_xml_syntax_error(xmlErrorConstPtr error); +void Nokogiri_error_array_pusher(void *ctx, xmlErrorConstPtr error); +NORETURN_DECL void Nokogiri_error_raise(void *ctx, xmlErrorConstPtr error); void Nokogiri_marshal_xpath_funcall_and_return_values(xmlXPathParserContextPtr ctx, int nargs, VALUE handler, const char *function_name) ; diff --git a/ext/nokogiri/test_global_handlers.c b/ext/nokogiri/test_global_handlers.c index 79bb6446612..cec0915fe89 100644 --- a/ext/nokogiri/test_global_handlers.c +++ b/ext/nokogiri/test_global_handlers.c @@ -3,7 +3,7 @@ static VALUE foreign_error_handler_block = Qnil; static void -foreign_error_handler(void *user_data, xmlErrorPtr c_error) +foreign_error_handler(void *user_data, xmlErrorConstPtr c_error) { rb_funcall(foreign_error_handler_block, rb_intern("call"), 0); } diff --git a/ext/nokogiri/xml_document.c b/ext/nokogiri/xml_document.c index bfaaf94f54e..7b4284bd944 100644 --- a/ext/nokogiri/xml_document.c +++ b/ext/nokogiri/xml_document.c @@ -337,7 +337,7 @@ read_io(VALUE klass, xmlSetStructuredErrorFunc(NULL, NULL); if (doc == NULL) { - xmlErrorPtr error; + xmlErrorConstPtr error; xmlFreeDoc(doc); @@ -383,7 +383,7 @@ read_memory(VALUE klass, xmlSetStructuredErrorFunc(NULL, NULL); if (doc == NULL) { - xmlErrorPtr error; + xmlErrorConstPtr error; xmlFreeDoc(doc); @@ -537,7 +537,7 @@ create_entity(int argc, VALUE *argv, VALUE self) ); if (NULL == ptr) { - xmlErrorPtr error = xmlGetLastError(); + xmlErrorConstPtr error = xmlGetLastError(); if (error) { rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error)); } else { diff --git a/ext/nokogiri/xml_node.c b/ext/nokogiri/xml_node.c index 01bd421d4d5..174c8319576 100644 --- a/ext/nokogiri/xml_node.c +++ b/ext/nokogiri/xml_node.c @@ -2138,7 +2138,7 @@ process_xincludes(VALUE self, VALUE options) xmlSetStructuredErrorFunc(NULL, NULL); if (rcode < 0) { - xmlErrorPtr error; + xmlErrorConstPtr error; error = xmlGetLastError(); if (error) { diff --git a/ext/nokogiri/xml_reader.c b/ext/nokogiri/xml_reader.c index d603b9829e4..3c78d50c879 100644 --- a/ext/nokogiri/xml_reader.c +++ b/ext/nokogiri/xml_reader.c @@ -554,7 +554,7 @@ static VALUE read_more(VALUE self) { xmlTextReaderPtr reader; - xmlErrorPtr error; + xmlErrorConstPtr error; VALUE error_list; int ret; diff --git a/ext/nokogiri/xml_relax_ng.c b/ext/nokogiri/xml_relax_ng.c index ddb53bff390..d18946b4bc2 100644 --- a/ext/nokogiri/xml_relax_ng.c +++ b/ext/nokogiri/xml_relax_ng.c @@ -93,7 +93,7 @@ xml_relax_ng_parse_schema( xmlRelaxNGFreeParserCtxt(c_parser_context); if (NULL == c_schema) { - xmlErrorPtr error = xmlGetLastError(); + xmlErrorConstPtr error = xmlGetLastError(); if (error) { Nokogiri_error_raise(NULL, error); } else { diff --git a/ext/nokogiri/xml_sax_push_parser.c b/ext/nokogiri/xml_sax_push_parser.c index 0181819d497..99694df2d6b 100644 --- a/ext/nokogiri/xml_sax_push_parser.c +++ b/ext/nokogiri/xml_sax_push_parser.c @@ -59,7 +59,7 @@ native_write(VALUE self, VALUE _chunk, VALUE _last_chunk) if (xmlParseChunk(ctx, chunk, size, Qtrue == _last_chunk ? 1 : 0)) { if (!(ctx->options & XML_PARSE_RECOVER)) { - xmlErrorPtr e = xmlCtxtGetLastError(ctx); + xmlErrorConstPtr e = xmlCtxtGetLastError(ctx); Nokogiri_error_raise(NULL, e); } } diff --git a/ext/nokogiri/xml_schema.c b/ext/nokogiri/xml_schema.c index a94c18d404d..3540d7496d3 100644 --- a/ext/nokogiri/xml_schema.c +++ b/ext/nokogiri/xml_schema.c @@ -146,7 +146,7 @@ xml_schema_parse_schema( xmlSchemaFreeParserCtxt(c_parser_context); if (NULL == c_schema) { - xmlErrorPtr error = xmlGetLastError(); + xmlErrorConstPtr error = xmlGetLastError(); if (error) { Nokogiri_error_raise(NULL, error); } else { diff --git a/ext/nokogiri/xml_syntax_error.c b/ext/nokogiri/xml_syntax_error.c index a5f0e1ad71f..473ccca30e8 100644 --- a/ext/nokogiri/xml_syntax_error.c +++ b/ext/nokogiri/xml_syntax_error.c @@ -26,7 +26,7 @@ Nokogiri_structured_error_func_restore(libxmlStructuredErrorHandlerState *handle } void -Nokogiri_error_array_pusher(void *ctx, xmlErrorPtr error) +Nokogiri_error_array_pusher(void *ctx, xmlErrorConstPtr error) { VALUE list = (VALUE)ctx; Check_Type(list, T_ARRAY); @@ -34,13 +34,13 @@ Nokogiri_error_array_pusher(void *ctx, xmlErrorPtr error) } void -Nokogiri_error_raise(void *ctx, xmlErrorPtr error) +Nokogiri_error_raise(void *ctx, xmlErrorConstPtr error) { rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error)); } VALUE -Nokogiri_wrap_xml_syntax_error(xmlErrorPtr error) +Nokogiri_wrap_xml_syntax_error(xmlErrorConstPtr error) { VALUE msg, e, klass; From e6314df23999bed532694a0e12604e6b2a52bbce Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 17 Nov 2023 14:11:30 -0500 Subject: [PATCH 4/6] ext: link libxml2 with `-lpthread` when necessary libxml 2.12 has a hard dependency on pthread symbols on older systems with glibc version < 2.34. note that we also remove the patch for libxml threaded support from 2.11, since we're now explicitly specifying libpthread. --- ext/nokogiri/extconf.rb | 8 +++++ ...bxml2-s-libc_single_threaded-support.patch | 30 ------------------- 2 files changed, 8 insertions(+), 30 deletions(-) delete mode 100644 patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch diff --git a/ext/nokogiri/extconf.rb b/ext/nokogiri/extconf.rb index 33e9963ef48..4a9c3b9fd62 100644 --- a/ext/nokogiri/extconf.rb +++ b/ext/nokogiri/extconf.rb @@ -884,6 +884,7 @@ def configure cppflags = concat_flags(ENV["CPPFLAGS"]) cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g") + libs = "" if cross_build_p cppflags = concat_flags(cppflags, "-DNOKOGIRI_PRECOMPILED_LIBRARIES") @@ -913,6 +914,12 @@ def configure "--disable-dependency-tracking" end + # glibc 2.34 and later merged libpthread into libc, but we still need to know if it exists so we + # can link libxml2 against it. + if local_have_library("pthread", "pthread_key_delete") + libs = concat_flags(libs, "-lpthread") + end + recipe.configure_options += [ "--without-python", "--without-readline", @@ -921,6 +928,7 @@ def configure "--with-threads", "CPPFLAGS=#{cppflags}", "CFLAGS=#{cflags}", + "LIBS=#{libs}", ] end diff --git a/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch b/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch deleted file mode 100644 index df5b77300dd..00000000000 --- a/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch +++ /dev/null @@ -1,30 +0,0 @@ -From fb618bd27ac7a9fd32973320016c7ff28dd2f60e Mon Sep 17 00:00:00 2001 -From: Mike Dalessio -Date: Fri, 5 May 2023 10:10:43 -0400 -Subject: [PATCH] rip out libxml2's libc_single_threaded support - -This is a preventative measure because this feature relies on a glibc -version we can't realistically require of users today. We're not yet -precompiling on a system with a modern-enough glibc to make this an -actual problem, but I'm doing it while all of this context is fresh. ---- - threads.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/threads.c b/threads.c -index 60dbce4c..eb1c12e5 100644 ---- a/threads.c -+++ b/threads.c -@@ -27,7 +27,8 @@ - - #if defined(HAVE_POSIX_THREADS) && \ - defined(__GLIBC__) && \ -- __GLIBC__ * 100 + __GLIBC_MINOR__ >= 234 -+ __GLIBC__ * 100 + __GLIBC_MINOR__ >= 234 && \ -+ !defined(NOKOGIRI_PRECOMPILED_LIBRARIES) - - /* - * The modern way available since glibc 2.32. --- -2.40.1 - From 985d15bb7ce41f7b65fc778b8e6a950ee744b509 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 17 Nov 2023 14:58:53 -0500 Subject: [PATCH 5/6] ext: allow libpthread in native platform gems --- rakelib/extensions.rake | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/rakelib/extensions.rake b/rakelib/extensions.rake index cb2881436a0..c1dd5566046 100644 --- a/rakelib/extensions.rake +++ b/rakelib/extensions.rake @@ -141,6 +141,7 @@ CrossRuby = Struct.new(:version, :platform) do "ws2_32.dll", "user32.dll", "advapi32.dll", + "libwinpthread-1.dll", libruby_dll, ] when MINGWUCRT_PLATFORM_REGEX @@ -160,6 +161,7 @@ CrossRuby = Struct.new(:version, :platform) do "api-ms-win-crt-string-l1-1-0.dll", "api-ms-win-crt-time-l1-1-0.dll", "api-ms-win-crt-utility-l1-1-0.dll", + "libwinpthread-1.dll", libruby_dll, ] when X86_LINUX_PLATFORM_REGEX @@ -167,18 +169,18 @@ CrossRuby = Struct.new(:version, :platform) do "libm.so.6", "libc.so.6", "libdl.so.2", # on old dists only - now in libc - ].tap do |dlls| - dlls << "libpthread.so.0" if ver >= "3.2.0" - end + "libpthread.so.0", # on old dists only - now in libc + "ld-linux.so.2", + "ld-linux-x86-64.so.2", + ] when AARCH_LINUX_PLATFORM_REGEX [ "libm.so.6", "libc.so.6", "libdl.so.2", # on old dists only - now in libc + "libpthread.so.0", # on old dists only - now in libc "ld-linux-aarch64.so.1", - ].tap do |dlls| - dlls << "libpthread.so.0" if ver >= "3.2.0" - end + ] when DARWIN_PLATFORM_REGEX [ "/usr/lib/libSystem.B.dylib", @@ -188,12 +190,11 @@ CrossRuby = Struct.new(:version, :platform) do when ARM_LINUX_PLATFORM_REGEX [ "libm.so.6", - "libdl.so.2", "libc.so.6", + "libdl.so.2", # on old dists only - now in libc + "libpthread.so.0", # on old dists only - now in libc "ld-linux-armhf.so.3", - ].tap do |dlls| - dlls << "libpthread.so.0" if ver >= "3.2.0" - end + ] else raise "CrossRuby.allowed_dlls: unmatched platform: #{platform}" end From 340dc31a175eec754af17a12a6af70550279dc7e Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Sat, 18 Nov 2023 09:31:09 -0500 Subject: [PATCH 6/6] ci: test compiling packaged libraries on musl because link-time behavior is important for the libpthread changes being made. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61798b3a75e..756f7d4330b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,7 +151,7 @@ jobs: strategy: fail-fast: false matrix: - sys: ["enable"] + sys: ["enable", "disable"] runs-on: ubuntu-latest container: image: ghcr.io/sparklemotion/nokogiri-test:alpine