makiri 0.7.0-x64-mingw-ucrt
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +74 -0
- data/.github/workflows/conformance.yml +116 -0
- data/.github/workflows/libfuzzer.yml +83 -0
- data/.github/workflows/release.yml +249 -0
- data/.github/workflows/security.yml +180 -0
- data/.github/workflows/valgrind.yml +138 -0
- data/.github/workflows/verify.yml +37 -0
- data/.gitmodules +3 -0
- data/CHANGELOG.md +425 -0
- data/LICENSE +176 -0
- data/NOTICE +12 -0
- data/README.md +334 -0
- data/Rakefile +464 -0
- data/lib/makiri/3.2/makiri.so +0 -0
- data/lib/makiri/3.3/makiri.so +0 -0
- data/lib/makiri/3.4/makiri.so +0 -0
- data/lib/makiri/4.0/makiri.so +0 -0
- data/lib/makiri/attr.rb +14 -0
- data/lib/makiri/cdata_section.rb +19 -0
- data/lib/makiri/comment.rb +14 -0
- data/lib/makiri/compat_aliases.rb +19 -0
- data/lib/makiri/css.rb +11 -0
- data/lib/makiri/document.rb +18 -0
- data/lib/makiri/document_fragment.rb +26 -0
- data/lib/makiri/document_type.rb +14 -0
- data/lib/makiri/element.rb +17 -0
- data/lib/makiri/html/document.rb +105 -0
- data/lib/makiri/html/node_methods.rb +18 -0
- data/lib/makiri/html.rb +12 -0
- data/lib/makiri/node.rb +264 -0
- data/lib/makiri/node_set.rb +118 -0
- data/lib/makiri/processing_instruction.rb +26 -0
- data/lib/makiri/text.rb +16 -0
- data/lib/makiri/version.rb +5 -0
- data/lib/makiri/xml/builder.rb +271 -0
- data/lib/makiri/xml/document.rb +24 -0
- data/lib/makiri/xml/node_methods.rb +84 -0
- data/lib/makiri/xml.rb +10 -0
- data/lib/makiri/xpath.rb +14 -0
- data/lib/makiri/xpath_context.rb +49 -0
- data/lib/makiri.rb +66 -0
- data/script/build_native_gem.rb +50 -0
- data/script/check_alloc_failures.rb +266 -0
- data/script/check_c_safety.rb +324 -0
- data/script/check_c_safety_allowlist.yml +108 -0
- data/script/check_leaks.rb +64 -0
- data/script/leaks_harness.rb +71 -0
- data/sig/makiri.rbs +4 -0
- data/suppressions/ruby.supp +162 -0
- data/verify/Makefile +237 -0
- data/verify/cbmc_models.c +38 -0
- data/verify/harness_alloc.c +257 -0
- data/verify/harness_buf.c +167 -0
- data/verify/harness_hash.c +28 -0
- data/verify/harness_span.c +213 -0
- data/verify/harness_spanbuf.c +98 -0
- data/verify/harness_utf8.c +70 -0
- data/verify/harness_utf8_chain.c +64 -0
- data/verify/harness_utf8_words.c +54 -0
- data/verify/harness_xml_chars.c +59 -0
- data/verify/harness_xml_expand.c +72 -0
- data/verify/harness_xml_parse.c +42 -0
- data/verify/harness_xpath_lex.c +51 -0
- data/verify/harness_xpath_number.c +68 -0
- data/verify/harness_xpath_parse.c +57 -0
- data/verify/selftest_main.c +16 -0
- data/verify/stub.c +10 -0
- data/verify/verify.h +54 -0
- metadata +161 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 2eb7b21bb34a15cc0263881ecf90715fac3263521b58dfd27b5d0ca966738402
|
|
4
|
+
data.tar.gz: 6a570d13671d4ecb8e85a235800a4c9ddf22e63d34c92cebe50c51d89551320c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c552c96226c3a75ad96f9d23a68021c2a4b4c562060ac1fe8392ebd4274fa5216814de1e63ee96149060d85e2293f808b1709e0717a9ca87b004216f91bca053
|
|
7
|
+
data.tar.gz: 7fe9bcdf19dcbb900d8ddf87712ca7f3bc74e532eda2cc5594d267da690eafd9f4aae0cfb62fec75021496c35b4cc01500ba6b991d8d86a1638aab7f106f544e
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
name: Ruby ${{ matrix.ruby }} on ${{ matrix.os }}
|
|
11
|
+
runs-on: ${{ matrix.os }}
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
16
|
+
ruby: ["3.2", "3.3", "3.4", "4.0"]
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout (with vendored Lexbor submodule)
|
|
20
|
+
uses: actions/checkout@v6
|
|
21
|
+
with:
|
|
22
|
+
submodules: recursive
|
|
23
|
+
|
|
24
|
+
- name: Ensure cmake is available
|
|
25
|
+
uses: lukka/get-cmake@latest
|
|
26
|
+
|
|
27
|
+
- name: Set up Ruby
|
|
28
|
+
uses: ruby/setup-ruby@v1
|
|
29
|
+
with:
|
|
30
|
+
ruby-version: ${{ matrix.ruby }}
|
|
31
|
+
bundler-cache: true
|
|
32
|
+
|
|
33
|
+
- name: Compile the extension (builds vendored Lexbor, then the ext)
|
|
34
|
+
run: bundle exec rake compile
|
|
35
|
+
|
|
36
|
+
# The :threading suite is heavy (GC.stress across threads) and checks a
|
|
37
|
+
# structural property that does not vary by OS/Ruby, so run it on a single
|
|
38
|
+
# representative job; the rest of the matrix skips it for a fast run.
|
|
39
|
+
- name: Run the test suite
|
|
40
|
+
run: bundle exec rake spec
|
|
41
|
+
env:
|
|
42
|
+
THREADING: ${{ (matrix.os == 'ubuntu-latest' && matrix.ruby == '3.4') && '1' || '' }}
|
|
43
|
+
|
|
44
|
+
- name: Smoke-load the gem
|
|
45
|
+
shell: bash
|
|
46
|
+
run: bundle exec ruby -Ilib -r makiri -e 'p Makiri::VERSION'
|
|
47
|
+
|
|
48
|
+
sanitize:
|
|
49
|
+
name: AddressSanitizer + UBSan (Ruby ${{ matrix.ruby }})
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
strategy:
|
|
52
|
+
fail-fast: false
|
|
53
|
+
matrix:
|
|
54
|
+
ruby: ["3.4", "4.0"]
|
|
55
|
+
steps:
|
|
56
|
+
- name: Checkout (with vendored Lexbor submodule)
|
|
57
|
+
uses: actions/checkout@v6
|
|
58
|
+
with:
|
|
59
|
+
submodules: recursive
|
|
60
|
+
|
|
61
|
+
- name: Ensure cmake is available
|
|
62
|
+
uses: lukka/get-cmake@latest
|
|
63
|
+
|
|
64
|
+
- name: Set up Ruby
|
|
65
|
+
uses: ruby/setup-ruby@v1
|
|
66
|
+
with:
|
|
67
|
+
ruby-version: ${{ matrix.ruby }}
|
|
68
|
+
bundler-cache: true
|
|
69
|
+
|
|
70
|
+
# Builds the ext with -fsanitize=address,undefined and runs the whole
|
|
71
|
+
# spec suite with the ASan runtime preloaded. Any heap/UB error aborts
|
|
72
|
+
# the run with a non-zero exit, failing the job.
|
|
73
|
+
- name: Build + test under sanitizers
|
|
74
|
+
run: bundle exec rake sanitize
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
name: Conformance
|
|
2
|
+
|
|
3
|
+
# Differential / spec-conformance suites. These compare Makiri against external
|
|
4
|
+
# references (Nokogiri's libxml2/Gumbo XPath+CSS, the html5lib-tests corpus) and
|
|
5
|
+
# catch semantic divergences that the unit specs cannot. The XPath and CSS
|
|
6
|
+
# differentials run OUTSIDE the bundle (the rake tasks use
|
|
7
|
+
# Bundler.with_unbundled_env), so Nokogiri — a bench-only dependency — must be
|
|
8
|
+
# present as a system gem; each job installs it explicitly.
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [main, master]
|
|
13
|
+
pull_request:
|
|
14
|
+
schedule:
|
|
15
|
+
- cron: "37 5 * * *" # nightly, offset from the other workflows
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
# PR + push: HTML5 parsing conformance, plus the XPath and CSS differentials
|
|
20
|
+
# over the curated corpus and a moderate batch of generated XPath expressions.
|
|
21
|
+
conformance:
|
|
22
|
+
name: HTML5 + XPath/CSS differential vs Nokogiri
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
if: github.event_name != 'schedule'
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout (with vendored Lexbor submodule)
|
|
27
|
+
uses: actions/checkout@v6
|
|
28
|
+
with:
|
|
29
|
+
submodules: recursive
|
|
30
|
+
|
|
31
|
+
- name: Ensure cmake is available
|
|
32
|
+
uses: lukka/get-cmake@latest
|
|
33
|
+
|
|
34
|
+
- name: Set up Ruby
|
|
35
|
+
uses: ruby/setup-ruby@v1
|
|
36
|
+
with:
|
|
37
|
+
ruby-version: "3.4"
|
|
38
|
+
bundler-cache: true
|
|
39
|
+
|
|
40
|
+
- name: Compile the extension (builds vendored Lexbor, then the ext)
|
|
41
|
+
run: bundle exec rake compile
|
|
42
|
+
|
|
43
|
+
- name: Install Nokogiri (system gem; the differentials run outside the bundle)
|
|
44
|
+
run: gem install --no-document nokogiri
|
|
45
|
+
|
|
46
|
+
- name: HTML5 parsing conformance (html5lib-tests)
|
|
47
|
+
run: bundle exec rake conformance:html5
|
|
48
|
+
|
|
49
|
+
# XPATH_ARGS must be a real env var, not a rake CLI arg: the task reads
|
|
50
|
+
# ENV['XPATH_ARGS'] inside Bundler.with_unbundled_env, which reverts to the
|
|
51
|
+
# pre-rake environment, so a rake-set var would be dropped.
|
|
52
|
+
- name: XPath 1.0 differential vs Nokogiri (corpus + generated)
|
|
53
|
+
run: bundle exec rake conformance:xpath
|
|
54
|
+
env:
|
|
55
|
+
XPATH_ARGS: "--generate 5000 --seed 1"
|
|
56
|
+
|
|
57
|
+
- name: CSS Selectors differential vs Nokogiri::HTML5
|
|
58
|
+
run: bundle exec rake conformance:css
|
|
59
|
+
|
|
60
|
+
- name: XML XPath 1.0 differential vs Nokogiri::XML
|
|
61
|
+
run: bundle exec rake conformance:xpath_xml
|
|
62
|
+
|
|
63
|
+
- name: XML CSS-selector differential vs Nokogiri::XML
|
|
64
|
+
run: bundle exec rake conformance:css_xml
|
|
65
|
+
|
|
66
|
+
- name: XML Builder differential vs Nokogiri::XML::Builder
|
|
67
|
+
run: bundle exec rake conformance:builder
|
|
68
|
+
|
|
69
|
+
# Nightly: a wide XPath differential sweep across many seeds and a high
|
|
70
|
+
# generated volume, to surface divergences the curated corpus and a single
|
|
71
|
+
# seed miss. Fails fast (bash -e) on the first real divergence.
|
|
72
|
+
conformance-nightly:
|
|
73
|
+
name: Nightly XPath differential sweep
|
|
74
|
+
runs-on: ubuntu-latest
|
|
75
|
+
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
|
|
76
|
+
steps:
|
|
77
|
+
- name: Checkout (with vendored Lexbor submodule)
|
|
78
|
+
uses: actions/checkout@v6
|
|
79
|
+
with:
|
|
80
|
+
submodules: recursive
|
|
81
|
+
|
|
82
|
+
- name: Ensure cmake is available
|
|
83
|
+
uses: lukka/get-cmake@latest
|
|
84
|
+
|
|
85
|
+
- name: Set up Ruby
|
|
86
|
+
uses: ruby/setup-ruby@v1
|
|
87
|
+
with:
|
|
88
|
+
ruby-version: "3.4"
|
|
89
|
+
bundler-cache: true
|
|
90
|
+
|
|
91
|
+
- name: Compile the extension
|
|
92
|
+
run: bundle exec rake compile
|
|
93
|
+
|
|
94
|
+
- name: Install Nokogiri (system gem)
|
|
95
|
+
run: gem install --no-document nokogiri
|
|
96
|
+
|
|
97
|
+
- name: XPath differential sweep (many seeds, high volume)
|
|
98
|
+
run: |
|
|
99
|
+
for seed in 1 2 3 4 5 6 7 8; do
|
|
100
|
+
echo "::group::seed ${seed}"
|
|
101
|
+
XPATH_ARGS="--generate 20000 --seed ${seed}" bundle exec rake conformance:xpath
|
|
102
|
+
echo "::endgroup::"
|
|
103
|
+
done
|
|
104
|
+
|
|
105
|
+
# The W3C XML conformance suite fetches its (pinned) test corpus on first
|
|
106
|
+
# run, so it lives in the nightly rather than on every PR.
|
|
107
|
+
- name: XML 1.0 well-formedness vs the W3C XML Conformance Test Suite
|
|
108
|
+
run: bundle exec rake conformance:xmlconf
|
|
109
|
+
|
|
110
|
+
# Property-based tree differential: generated documents, Makiri's parsed
|
|
111
|
+
# tree + canonical output vs Nokogiri::XML. Scalable volume - nightly gets
|
|
112
|
+
# a much larger batch than the resident in-suite PBT specs.
|
|
113
|
+
- name: XML property-based tree differential vs Nokogiri::XML
|
|
114
|
+
run: bundle exec rake conformance:xml_pbt
|
|
115
|
+
env:
|
|
116
|
+
PBT_ARGS: "--count 20000"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
name: libFuzzer
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Nightly: libFuzzer runs are coverage-guided and long-running; they complement
|
|
5
|
+
# the PR-level short fuzz (30s) and the nightly sanitizer fuzz (300s per target).
|
|
6
|
+
# We run them on a schedule because the coverage signal needs sustained CPU
|
|
7
|
+
# time to reach deep branches (e.g. DOCTYPE quote/bracket state machine,
|
|
8
|
+
# reference expansion boundaries).
|
|
9
|
+
schedule:
|
|
10
|
+
- cron: "0 3 * * *"
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
# Build the libFuzzer harnesses under clang with -fsanitize=fuzzer,address
|
|
15
|
+
# and run each target for 300s. The corpus is stored as a build artifact so
|
|
16
|
+
# it can be seeded in subsequent runs (regression asset per the roadmap).
|
|
17
|
+
libfuzzer-nightly:
|
|
18
|
+
name: libFuzzer ${{ matrix.target }} (clang)
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
timeout-minutes: 360
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
target: [xml, xpath, xml_xpath]
|
|
25
|
+
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout (with vendored Lexbor submodule)
|
|
28
|
+
uses: actions/checkout@v6
|
|
29
|
+
with:
|
|
30
|
+
submodules: recursive
|
|
31
|
+
|
|
32
|
+
- name: Ensure cmake is available
|
|
33
|
+
uses: lukka/get-cmake@latest
|
|
34
|
+
|
|
35
|
+
- name: Set up Ruby
|
|
36
|
+
uses: ruby/setup-ruby@v1
|
|
37
|
+
with:
|
|
38
|
+
ruby-version: "3.4"
|
|
39
|
+
bundler-cache: true
|
|
40
|
+
|
|
41
|
+
# Build the vendored Lexbor first (plain mode is fine; the harness links
|
|
42
|
+
# the static archive). The fuzzer binary itself is built with ASan.
|
|
43
|
+
- name: Compile the extension (builds Lexbor)
|
|
44
|
+
run: bundle exec rake compile
|
|
45
|
+
|
|
46
|
+
- name: Install clang
|
|
47
|
+
run: |
|
|
48
|
+
sudo apt-get update
|
|
49
|
+
sudo apt-get install -y clang
|
|
50
|
+
|
|
51
|
+
- name: Build libFuzzer harnesses
|
|
52
|
+
run: |
|
|
53
|
+
cd ext/makiri/fuzz
|
|
54
|
+
make clean
|
|
55
|
+
make all
|
|
56
|
+
|
|
57
|
+
# Restore the previous corpus so the fuzzer starts from the accumulated
|
|
58
|
+
# regression seeds rather than from scratch.
|
|
59
|
+
- name: Restore corpus cache
|
|
60
|
+
uses: actions/cache@v4
|
|
61
|
+
with:
|
|
62
|
+
path: ext/makiri/fuzz/corpus/${{ matrix.target }}
|
|
63
|
+
key: libfuzzer-corpus-${{ matrix.target }}-${{ github.run_id }}
|
|
64
|
+
restore-keys: |
|
|
65
|
+
libfuzzer-corpus-${{ matrix.target }}-
|
|
66
|
+
|
|
67
|
+
- name: Run libFuzzer ${{ matrix.target }} (300s)
|
|
68
|
+
run: |
|
|
69
|
+
mkdir -p ext/makiri/fuzz/corpus/${{ matrix.target }}
|
|
70
|
+
cd ext/makiri/fuzz
|
|
71
|
+
./${{ matrix.target }}_fuzz \
|
|
72
|
+
-max_total_time=300 \
|
|
73
|
+
-max_len=4096 \
|
|
74
|
+
-print_final_stats=1 \
|
|
75
|
+
corpus/${{ matrix.target }}
|
|
76
|
+
|
|
77
|
+
# Save the mutated corpus as an artifact for download / seeding.
|
|
78
|
+
- name: Upload corpus artifact
|
|
79
|
+
uses: actions/upload-artifact@v4
|
|
80
|
+
with:
|
|
81
|
+
name: libfuzzer-corpus-${{ matrix.target }}
|
|
82
|
+
path: ext/makiri/fuzz/corpus/${{ matrix.target }}
|
|
83
|
+
retention-days: 7
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Build the source gem and precompiled ("fat") native gems for the major
|
|
4
|
+
# platforms, attach them to a GitHub Release, and (optionally, on manual
|
|
5
|
+
# dispatch) publish to RubyGems.
|
|
6
|
+
#
|
|
7
|
+
# Native gems are built on each target platform's own runner — NOT
|
|
8
|
+
# cross-compiled — because the extension builds vendored Lexbor with CMake using
|
|
9
|
+
# the host toolchain (see ext/makiri/extconf.rb). Each runner compiles for
|
|
10
|
+
# Ruby 3.2/3.3/3.4; script/build_native_gem.rb then assembles one gem per
|
|
11
|
+
# platform containing all three ABIs (lib/makiri.rb selects the right one at
|
|
12
|
+
# require time). `gem install` of a native gem does not recompile or need
|
|
13
|
+
# cmake / the Lexbor submodule.
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
push:
|
|
17
|
+
tags: ["v*"]
|
|
18
|
+
workflow_dispatch:
|
|
19
|
+
inputs:
|
|
20
|
+
publish_to_rubygems:
|
|
21
|
+
description: "Push the built gems to RubyGems (via Trusted Publishing / OIDC)"
|
|
22
|
+
type: boolean
|
|
23
|
+
default: false
|
|
24
|
+
|
|
25
|
+
permissions:
|
|
26
|
+
contents: write # create the GitHub Release and upload assets
|
|
27
|
+
|
|
28
|
+
env:
|
|
29
|
+
RUBY_ABIS: "3.2 3.3 3.4 4.0" # Ruby minor versions a native gem serves
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
# --- source gem (always builds; compiles from source at install time) -------
|
|
33
|
+
source-gem:
|
|
34
|
+
name: Source gem
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v6
|
|
38
|
+
with:
|
|
39
|
+
submodules: recursive # vendored Lexbor must be in the gem's file list
|
|
40
|
+
- uses: ruby/setup-ruby@v1
|
|
41
|
+
with:
|
|
42
|
+
ruby-version: "3.4"
|
|
43
|
+
- name: Build source gem
|
|
44
|
+
run: |
|
|
45
|
+
mkdir -p pkg
|
|
46
|
+
gem build makiri.gemspec -o pkg/makiri-source.gem
|
|
47
|
+
- uses: actions/upload-artifact@v7
|
|
48
|
+
with:
|
|
49
|
+
name: gem-source
|
|
50
|
+
path: pkg/*.gem
|
|
51
|
+
if-no-files-found: error
|
|
52
|
+
|
|
53
|
+
# --- compile the extension natively, per platform x Ruby --------------------
|
|
54
|
+
compile:
|
|
55
|
+
name: Compile ${{ matrix.platform }} (Ruby ${{ matrix.ruby }})
|
|
56
|
+
runs-on: ${{ matrix.os }}
|
|
57
|
+
strategy:
|
|
58
|
+
fail-fast: false
|
|
59
|
+
matrix:
|
|
60
|
+
ruby: ["3.2", "3.3", "3.4", "4.0"]
|
|
61
|
+
platform:
|
|
62
|
+
- x86_64-linux
|
|
63
|
+
- aarch64-linux
|
|
64
|
+
- arm64-darwin
|
|
65
|
+
- x64-mingw-ucrt
|
|
66
|
+
include:
|
|
67
|
+
- { platform: x86_64-linux, os: ubuntu-latest }
|
|
68
|
+
- { platform: aarch64-linux, os: ubuntu-24.04-arm }
|
|
69
|
+
- { platform: arm64-darwin, os: macos-14 }
|
|
70
|
+
- { platform: x64-mingw-ucrt, os: windows-latest }
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@v6
|
|
73
|
+
with:
|
|
74
|
+
submodules: recursive
|
|
75
|
+
- name: Ensure cmake is available
|
|
76
|
+
uses: lukka/get-cmake@latest
|
|
77
|
+
- uses: ruby/setup-ruby@v1
|
|
78
|
+
with:
|
|
79
|
+
ruby-version: ${{ matrix.ruby }}
|
|
80
|
+
bundler-cache: true
|
|
81
|
+
- name: Compile (builds vendored Lexbor, then the ext)
|
|
82
|
+
run: bundle exec rake compile
|
|
83
|
+
- name: Smoke-load
|
|
84
|
+
shell: bash
|
|
85
|
+
run: bundle exec ruby -Ilib -r makiri -e 'p Makiri::VERSION'
|
|
86
|
+
- name: Stage the compiled binary under its ABI subdir
|
|
87
|
+
shell: bash
|
|
88
|
+
run: |
|
|
89
|
+
minor="$(ruby -e 'print RUBY_VERSION[/\d+\.\d+/]')"
|
|
90
|
+
dlext="$(ruby -e 'print RbConfig::CONFIG["DLEXT"]')" # so | bundle
|
|
91
|
+
mkdir -p "artifact/${minor}"
|
|
92
|
+
cp "lib/makiri/makiri.${dlext}" "artifact/${minor}/makiri.${dlext}"
|
|
93
|
+
ls -l "artifact/${minor}"
|
|
94
|
+
- name: Assert the binary is Ruby-portable (no libruby hard-link)
|
|
95
|
+
shell: bash
|
|
96
|
+
# extconf.rb builds the extension with dynamic_lookup / no libruby link so
|
|
97
|
+
# one precompiled binary loads on any compatible Ruby of that ABI. If a
|
|
98
|
+
# change reintroduces a libruby dependency, the gem would only load on the
|
|
99
|
+
# exact build Ruby — fail loudly here instead of shipping a broken gem.
|
|
100
|
+
run: |
|
|
101
|
+
dlext="$(ruby -e 'print RbConfig::CONFIG["DLEXT"]')"
|
|
102
|
+
bin="lib/makiri/makiri.${dlext}"
|
|
103
|
+
case "$(uname -s)" in
|
|
104
|
+
Darwin)
|
|
105
|
+
if otool -L "$bin" | grep -i 'libruby'; then
|
|
106
|
+
echo "::error::$bin hard-links libruby; precompiled gem would not load on other Ruby installs"; exit 1
|
|
107
|
+
fi
|
|
108
|
+
;;
|
|
109
|
+
MINGW*|MSYS*|CYGWIN*)
|
|
110
|
+
# Windows PE DLLs MUST import the Ruby DLL via the import library
|
|
111
|
+
# (no dynamic_lookup on PE/COFF). A libruby import here is by design,
|
|
112
|
+
# not a portability bug, so this assertion does not apply.
|
|
113
|
+
echo "Windows (x64-mingw-ucrt): Ruby import-library link is by design; skipping libruby assertion"
|
|
114
|
+
;;
|
|
115
|
+
*)
|
|
116
|
+
if readelf -d "$bin" 2>/dev/null | grep -iE 'NEEDED.*libruby'; then
|
|
117
|
+
echo "::error::$bin has a libruby NEEDED entry; precompiled gem may not load on a static Ruby"; exit 1
|
|
118
|
+
fi
|
|
119
|
+
;;
|
|
120
|
+
esac
|
|
121
|
+
echo "OK: portability check complete for $bin"
|
|
122
|
+
- uses: actions/upload-artifact@v7
|
|
123
|
+
with:
|
|
124
|
+
name: bin-${{ matrix.platform }}-${{ matrix.ruby }}
|
|
125
|
+
path: artifact/
|
|
126
|
+
if-no-files-found: error
|
|
127
|
+
|
|
128
|
+
# --- assemble one fat gem per platform from its per-ABI binaries ------------
|
|
129
|
+
native-gem:
|
|
130
|
+
name: Native gem ${{ matrix.platform }}
|
|
131
|
+
needs: compile
|
|
132
|
+
runs-on: ${{ matrix.os }}
|
|
133
|
+
strategy:
|
|
134
|
+
fail-fast: false
|
|
135
|
+
matrix:
|
|
136
|
+
include:
|
|
137
|
+
- platform: x86_64-linux
|
|
138
|
+
os: ubuntu-latest
|
|
139
|
+
- platform: aarch64-linux
|
|
140
|
+
os: ubuntu-24.04-arm
|
|
141
|
+
- platform: arm64-darwin
|
|
142
|
+
os: macos-14
|
|
143
|
+
- platform: x64-mingw-ucrt
|
|
144
|
+
os: windows-latest
|
|
145
|
+
steps:
|
|
146
|
+
- uses: actions/checkout@v6
|
|
147
|
+
with:
|
|
148
|
+
submodules: recursive # for the gemspec's file scan (ext/vendor are then dropped)
|
|
149
|
+
- uses: ruby/setup-ruby@v1
|
|
150
|
+
with:
|
|
151
|
+
ruby-version: "3.4"
|
|
152
|
+
- name: Download this platform's per-ABI binaries
|
|
153
|
+
uses: actions/download-artifact@v8
|
|
154
|
+
with:
|
|
155
|
+
pattern: bin-${{ matrix.platform }}-*
|
|
156
|
+
merge-multiple: true
|
|
157
|
+
path: staged
|
|
158
|
+
- name: Place binaries under lib/makiri/<abi>/
|
|
159
|
+
shell: bash
|
|
160
|
+
run: |
|
|
161
|
+
mkdir -p lib/makiri
|
|
162
|
+
echo "Downloaded artifacts:"
|
|
163
|
+
find staged -maxdepth 3 -type f -print || true
|
|
164
|
+
if ! find staged -mindepth 2 -maxdepth 2 -name 'makiri.*' | grep -q .; then
|
|
165
|
+
echo "::error::No makiri binaries were downloaded for ${{ matrix.platform }}"
|
|
166
|
+
exit 1
|
|
167
|
+
fi
|
|
168
|
+
cp -r staged/* lib/makiri/
|
|
169
|
+
echo "Staged binaries:"
|
|
170
|
+
find lib/makiri -maxdepth 2 -name 'makiri.*' -print
|
|
171
|
+
- name: Build the native gem
|
|
172
|
+
run: ruby script/build_native_gem.rb "${{ matrix.platform }}"
|
|
173
|
+
- name: Verify it installs without recompiling
|
|
174
|
+
shell: bash
|
|
175
|
+
run: |
|
|
176
|
+
gem install "makiri-"*"-${{ matrix.platform }}.gem" --local
|
|
177
|
+
ruby -e 'require "makiri"; puts Makiri::VERSION'
|
|
178
|
+
- uses: actions/upload-artifact@v7
|
|
179
|
+
with:
|
|
180
|
+
name: gem-${{ matrix.platform }}
|
|
181
|
+
path: "*.gem"
|
|
182
|
+
if-no-files-found: error
|
|
183
|
+
|
|
184
|
+
# --- attach every gem to a GitHub Release (on a version tag) ----------------
|
|
185
|
+
release:
|
|
186
|
+
name: GitHub Release
|
|
187
|
+
needs: [source-gem, native-gem]
|
|
188
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
189
|
+
runs-on: ubuntu-latest
|
|
190
|
+
steps:
|
|
191
|
+
- uses: actions/download-artifact@v8
|
|
192
|
+
with:
|
|
193
|
+
pattern: gem-*
|
|
194
|
+
merge-multiple: true
|
|
195
|
+
path: dist
|
|
196
|
+
- name: List assets
|
|
197
|
+
run: ls -l dist
|
|
198
|
+
- name: Create / update the release
|
|
199
|
+
env:
|
|
200
|
+
GH_TOKEN: ${{ github.token }}
|
|
201
|
+
run: |
|
|
202
|
+
# Mark pre-release tags (v1.2.3.rc1 / -beta / -alpha / -pre) as such.
|
|
203
|
+
pre=""
|
|
204
|
+
case "$GITHUB_REF_NAME" in
|
|
205
|
+
*rc*|*beta*|*alpha*|*pre*) pre="--prerelease" ;;
|
|
206
|
+
esac
|
|
207
|
+
gh release create "${GITHUB_REF_NAME}" dist/*.gem \
|
|
208
|
+
--repo "${GITHUB_REPOSITORY}" \
|
|
209
|
+
--title "${GITHUB_REF_NAME}" \
|
|
210
|
+
--notes "Automated release for ${GITHUB_REF_NAME}. See CHANGELOG.md." \
|
|
211
|
+
$pre --verify-tag || \
|
|
212
|
+
gh release upload "${GITHUB_REF_NAME}" dist/*.gem --repo "${GITHUB_REPOSITORY}" --clobber
|
|
213
|
+
|
|
214
|
+
# --- publish to RubyGems, behind the `rubygems` environment approval gate ---
|
|
215
|
+
# Held until the `rubygems` environment's Required-reviewers rule is approved,
|
|
216
|
+
# so a tag push releases on GitHub immediately but the RubyGems push waits.
|
|
217
|
+
#
|
|
218
|
+
# Auth is RubyGems Trusted Publishing (OIDC): no stored API key. Configure a
|
|
219
|
+
# matching Trusted Publisher on RubyGems.org (owner=takahashim, repo=makiri,
|
|
220
|
+
# workflow=release.yml, Environment=rubygems) so the token is only accepted
|
|
221
|
+
# through this gated environment.
|
|
222
|
+
publish:
|
|
223
|
+
name: Publish to RubyGems
|
|
224
|
+
needs: [source-gem, native-gem]
|
|
225
|
+
if: >-
|
|
226
|
+
startsWith(github.ref, 'refs/tags/') ||
|
|
227
|
+
(github.event_name == 'workflow_dispatch' && inputs.publish_to_rubygems)
|
|
228
|
+
runs-on: ubuntu-latest
|
|
229
|
+
environment: rubygems
|
|
230
|
+
permissions:
|
|
231
|
+
contents: read
|
|
232
|
+
id-token: write # OIDC identity token for Trusted Publishing
|
|
233
|
+
steps:
|
|
234
|
+
- uses: ruby/setup-ruby@v1
|
|
235
|
+
with:
|
|
236
|
+
ruby-version: "3.4"
|
|
237
|
+
- uses: actions/download-artifact@v8
|
|
238
|
+
with:
|
|
239
|
+
pattern: gem-*
|
|
240
|
+
merge-multiple: true
|
|
241
|
+
path: dist
|
|
242
|
+
- name: Configure RubyGems credentials (OIDC trusted publishing)
|
|
243
|
+
uses: rubygems/configure-rubygems-credentials@762a4b77c3300434bb57c7ce80b20e36231927aa # v2.0.0
|
|
244
|
+
- name: gem push
|
|
245
|
+
run: |
|
|
246
|
+
for g in dist/*.gem; do
|
|
247
|
+
echo "Pushing $g"
|
|
248
|
+
gem push "$g"
|
|
249
|
+
done
|