ruact 0.0.1 → 0.0.3
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 +4 -4
- data/.codecov.yml +31 -0
- data/.github/workflows/ci.yml +160 -94
- data/.github/workflows/server-functions-bench.yml +54 -0
- data/.rubocop.yml +19 -1
- data/.rubocop_todo.yml +175 -0
- data/CHANGELOG.md +86 -5
- data/README.md +2 -0
- data/RELEASING.md +9 -3
- data/bench/server_functions_dispatch_bench.rb +309 -0
- data/bench/server_functions_dispatch_bench.results.md +121 -0
- data/docs/internal/README.md +9 -0
- data/docs/internal/decisions/server-functions-api.md +1680 -0
- data/lib/generators/ruact/install/install_generator.rb +43 -0
- data/lib/generators/ruact/install/templates/application.jsx.tt +1 -1
- data/lib/generators/ruact/install/templates/initializer.rb.tt +1 -1
- data/lib/ruact/client_manifest.rb +125 -12
- data/lib/ruact/configuration.rb +264 -23
- data/lib/ruact/controller.rb +459 -32
- data/lib/ruact/doctor.rb +34 -2
- data/lib/ruact/erb_preprocessor.rb +6 -6
- data/lib/ruact/errors.rb +89 -0
- data/lib/ruact/flight/serializer.rb +2 -2
- data/lib/ruact/html_converter.rb +131 -31
- data/lib/ruact/query.rb +107 -0
- data/lib/ruact/railtie.rb +220 -3
- data/lib/ruact/render_context.rb +30 -0
- data/lib/ruact/render_pipeline.rb +201 -59
- data/lib/ruact/routing.rb +81 -0
- data/lib/ruact/serializable.rb +11 -11
- data/lib/ruact/server.rb +341 -0
- data/lib/ruact/server_action.rb +131 -0
- data/lib/ruact/server_functions/backtrace_cleaner.rb +32 -0
- data/lib/ruact/server_functions/bucket_two_payload.rb +109 -0
- data/lib/ruact/server_functions/codegen.rb +330 -0
- data/lib/ruact/server_functions/codegen_v2.rb +176 -0
- data/lib/ruact/server_functions/endpoint_controller.rb +237 -0
- data/lib/ruact/server_functions/error_payload.rb +93 -0
- data/lib/ruact/server_functions/error_rendering.rb +188 -0
- data/lib/ruact/server_functions/error_suggestion.rb +38 -0
- data/lib/ruact/server_functions/name_bridge.rb +113 -0
- data/lib/ruact/server_functions/query_context.rb +62 -0
- data/lib/ruact/server_functions/query_dispatch.rb +248 -0
- data/lib/ruact/server_functions/registry.rb +148 -0
- data/lib/ruact/server_functions/registry_entry.rb +26 -0
- data/lib/ruact/server_functions/route_source.rb +201 -0
- data/lib/ruact/server_functions/snapshot.rb +195 -0
- data/lib/ruact/server_functions/snapshot_writer.rb +65 -0
- data/lib/ruact/server_functions/standalone_context.rb +103 -0
- data/lib/ruact/server_functions/standalone_dispatcher.rb +178 -0
- data/lib/ruact/server_functions.rb +75 -0
- data/lib/ruact/version.rb +1 -1
- data/lib/ruact/view_helper.rb +17 -9
- data/lib/ruact.rb +85 -6
- data/lib/rubocop/cop/ruact/no_shared_state.rb +1 -1
- data/lib/tasks/benchmark.rake +15 -11
- data/lib/tasks/ruact.rake +81 -0
- data/spec/benchmarks/render_pipeline_benchmark_spec.rb +1 -1
- data/spec/fixtures/flight/README.md +55 -7
- data/spec/fixtures/flight/bigint.txt +1 -0
- data/spec/fixtures/flight/infinity.txt +1 -0
- data/spec/fixtures/flight/nan.txt +1 -0
- data/spec/fixtures/flight/negative_infinity.txt +1 -0
- data/spec/fixtures/flight/undefined.txt +1 -0
- data/spec/fixtures/story_7_9_views/controller_request_spec_support/demo/show.html.erb +3 -0
- data/spec/ruact/client_manifest_spec.rb +108 -0
- data/spec/ruact/configuration_spec.rb +501 -0
- data/spec/ruact/controller_request_spec.rb +204 -0
- data/spec/ruact/controller_spec.rb +427 -39
- data/spec/ruact/doctor_spec.rb +118 -0
- data/spec/ruact/erb_preprocessor_hook_spec.rb +3 -3
- data/spec/ruact/erb_preprocessor_spec.rb +7 -7
- data/spec/ruact/errors_spec.rb +95 -0
- data/spec/ruact/flight/renderer_spec.rb +14 -3
- data/spec/ruact/flight/serializer_spec.rb +129 -88
- data/spec/ruact/html_converter_spec.rb +183 -5
- data/spec/ruact/install_generator_spec.rb +93 -0
- data/spec/ruact/query_request_spec.rb +446 -0
- data/spec/ruact/query_spec.rb +105 -0
- data/spec/ruact/railtie_spec.rb +2 -3
- data/spec/ruact/render_context_spec.rb +58 -0
- data/spec/ruact/render_pipeline_concurrency_spec.rb +78 -0
- data/spec/ruact/render_pipeline_spec.rb +784 -330
- data/spec/ruact/serializable_spec.rb +8 -8
- data/spec/ruact/server_bucket_request_spec.rb +352 -0
- data/spec/ruact/server_function_name_spec.rb +53 -0
- data/spec/ruact/server_functions/backtrace_cleaner_spec.rb +63 -0
- data/spec/ruact/server_functions/bucket_two_payload_spec.rb +200 -0
- data/spec/ruact/server_functions/codegen_spec.rb +429 -0
- data/spec/ruact/server_functions/csrf_request_spec.rb +380 -0
- data/spec/ruact/server_functions/dispatch_request_spec.rb +819 -0
- data/spec/ruact/server_functions/error_payload_spec.rb +222 -0
- data/spec/ruact/server_functions/error_suggestion_spec.rb +79 -0
- data/spec/ruact/server_functions/name_bridge_spec.rb +188 -0
- data/spec/ruact/server_functions/query_context_spec.rb +72 -0
- data/spec/ruact/server_functions/railtie_integration_spec.rb +345 -0
- data/spec/ruact/server_functions/rake_spec.rb +86 -0
- data/spec/ruact/server_functions/registry_spec.rb +199 -0
- data/spec/ruact/server_functions/route_source_spec.rb +202 -0
- data/spec/ruact/server_functions/snapshot_spec.rb +256 -0
- data/spec/ruact/server_functions/snapshot_writer_spec.rb +71 -0
- data/spec/ruact/server_functions/standalone_action_spec.rb +224 -0
- data/spec/ruact/server_functions/standalone_context_spec.rb +142 -0
- data/spec/ruact/server_functions/standalone_dispatcher_spec.rb +273 -0
- data/spec/ruact/server_rescue_request_spec.rb +416 -0
- data/spec/ruact/server_spec.rb +180 -0
- data/spec/ruact/server_upload_request_spec.rb +311 -0
- data/spec/ruact/view_helper_spec.rb +23 -17
- data/spec/spec_helper.rb +52 -1
- data/spec/support/fixtures/pixel.png +0 -0
- data/spec/support/flight_wire_parser.rb +135 -0
- data/spec/support/flight_wire_parser_spec.rb +93 -0
- data/spec/support/matchers/flight_fixture_matcher.rb +356 -0
- data/spec/support/matchers/flight_fixture_matcher_spec.rb +250 -0
- data/spec/support/rails_stub.rb +75 -5
- data/vendor/javascript/ruact-server-functions-runtime/index.d.ts +139 -0
- data/vendor/javascript/ruact-server-functions-runtime/index.js +438 -0
- data/vendor/javascript/ruact-server-functions-runtime/index.test.mjs +827 -0
- data/vendor/javascript/ruact-server-functions-runtime/package.json +22 -0
- data/vendor/javascript/vite-plugin-ruact/index.js +3 -2
- data/vendor/javascript/vite-plugin-ruact/package-lock.json +1429 -0
- data/vendor/javascript/vite-plugin-ruact/package.json +15 -0
- data/vendor/javascript/vite-plugin-ruact/server-functions-codegen.mjs +761 -0
- data/vendor/javascript/vite-plugin-ruact/server-functions-codegen.test.mjs +866 -0
- data/vendor/javascript/vite-plugin-ruact/vitest.config.mjs +15 -0
- metadata +87 -6
- data/Users/luiz/workspace/rails-rsc/gem/vendor/javascript/vite-plugin-ruact/index.js +0 -163
- data/lib/ruact/component_registry.rb +0 -31
- data/lib/tasks/rsc.rake +0 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce264ae503bd6e5c3239399e6bc39491724eec59b8f166a7e69923e40e2e0a10
|
|
4
|
+
data.tar.gz: 6ae79fc064960c97e8345a9030778dc61489c1179ea70123aad28a0de0806bf3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 660f2dbc8b3783eef80a3f935aa39a4afa34f02190578ada873fdd3074fe4182e77e9d5c486cd220edc68d89c8ff04581ab412eacd0bf3115c481841a4df9049
|
|
7
|
+
data.tar.gz: b4ddd9632c82d7a7d10e4113730bf4fedbd3b8b0007f917c4dc49fb880362e7b0b6a1bb7c2f953355d0926c39a893a7c377a693d0f8512330cfe226315e682cf
|
data/.codecov.yml
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Codecov configuration for the ruact gem.
|
|
2
|
+
# Story 6.7 — coverage is informativo (not a CI gate); Codecov reports status
|
|
3
|
+
# but never fails a PR. Diff coverage targets (90% line / 80% branch) are
|
|
4
|
+
# project DoD, surfaced via the per-PR comment for visibility.
|
|
5
|
+
|
|
6
|
+
coverage:
|
|
7
|
+
status:
|
|
8
|
+
project:
|
|
9
|
+
default:
|
|
10
|
+
informational: true
|
|
11
|
+
target: auto
|
|
12
|
+
threshold: 1%
|
|
13
|
+
patch:
|
|
14
|
+
default:
|
|
15
|
+
informational: true
|
|
16
|
+
target: 90%
|
|
17
|
+
threshold: 0%
|
|
18
|
+
|
|
19
|
+
comment:
|
|
20
|
+
layout: "diff, files"
|
|
21
|
+
behavior: default
|
|
22
|
+
require_changes: false
|
|
23
|
+
|
|
24
|
+
flags:
|
|
25
|
+
gem:
|
|
26
|
+
# Paths are relative to the gem repo root (where this CI runs and uploads
|
|
27
|
+
# from). lcov.info emits source paths like `./lib/ruact.rb`; Codecov
|
|
28
|
+
# normalizes the leading `./` so a `lib/` prefix matches.
|
|
29
|
+
paths:
|
|
30
|
+
- lib/
|
|
31
|
+
carryforward: false
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -6,7 +6,85 @@ on:
|
|
|
6
6
|
pull_request:
|
|
7
7
|
branches: [main]
|
|
8
8
|
|
|
9
|
+
# Note: this workflow runs in the `luizcg/ruact` repo, where the gem source
|
|
10
|
+
# lives at the repo root (no `gem/` subdirectory). The previous version had
|
|
11
|
+
# `working-directory: gem` on every step, copy-pasted from a monorepo layout;
|
|
12
|
+
# every run since the initial commit failed at `setup-ruby` with
|
|
13
|
+
# `ENOENT: no such file or directory, chdir 'gem'`. The e2e jobs depended
|
|
14
|
+
# on an `e2e/` Rails app that lives in the planning monorepo, not in this
|
|
15
|
+
# repo, and likewise could never run here. Both issues fixed in Story 6.7.
|
|
16
|
+
|
|
9
17
|
jobs:
|
|
18
|
+
name-propagation:
|
|
19
|
+
# Required status check — fails if the legacy gem name or the legacy
|
|
20
|
+
# API-surface prefix appear in user-facing files. Two complementary
|
|
21
|
+
# guards:
|
|
22
|
+
#
|
|
23
|
+
# (a) Story 5.1 — guards against the legacy gem-name regression
|
|
24
|
+
# (the `rails[_-]rsc` / PascalCase form). The legacy names are
|
|
25
|
+
# written here in the same regex-character-class form that the
|
|
26
|
+
# grep step itself uses, so this workflow file stays grep-clean
|
|
27
|
+
# under its own checks.
|
|
28
|
+
# (b) Story 5.12 — guards against the residual legacy prefix on the
|
|
29
|
+
# API surface (controller methods, header name, Rake task, view
|
|
30
|
+
# helper, token format, Serializable DSL) being re-introduced
|
|
31
|
+
# after the pre-v0.1.0 clean cut.
|
|
32
|
+
#
|
|
33
|
+
# Exclusion list mirrors the AC1 / AC6 contracts exactly: CHANGELOG.md
|
|
34
|
+
# (historical record), doc/ (generated YARD), *.gem (built artifacts).
|
|
35
|
+
name: No legacy gem-name or legacy-prefix API references
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v5
|
|
39
|
+
- name: Grep for legacy gem-name references (Story 5.1)
|
|
40
|
+
# Pattern is assembled from concatenated string fragments so this
|
|
41
|
+
# very workflow file is grep-clean even though it talks about the
|
|
42
|
+
# legacy names — that lets the canonical exclusion list stay at
|
|
43
|
+
# three entries (Story 5.1 review F4).
|
|
44
|
+
run: |
|
|
45
|
+
PATTERN='rails[_-]rsc|Rails''Rsc'
|
|
46
|
+
if git grep -nE "$PATTERN" -- \
|
|
47
|
+
':!CHANGELOG.md' \
|
|
48
|
+
':!doc/' \
|
|
49
|
+
':!*.gem'; then
|
|
50
|
+
echo "::error::Legacy gem-name reference found in user-facing file."
|
|
51
|
+
echo "::error::Rename to 'ruact' / 'Ruact'. See Story 5.1 in _bmad-output/implementation-artifacts/."
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
echo "::notice::No legacy gem-name references found."
|
|
55
|
+
- name: Grep for residual rsc_* API references (Story 5.12)
|
|
56
|
+
# AC1 of Story 5.12: every identifier renamed in the clean cut.
|
|
57
|
+
# Uses Perl mode (-P) for word boundaries. Pattern fragments are
|
|
58
|
+
# split with $R / $RU shell-vars so this workflow file is itself
|
|
59
|
+
# grep-clean — the file contains `${R}` / `${RU}` references, not
|
|
60
|
+
# literal `rsc` / `RSC` strings that would match the pattern (same
|
|
61
|
+
# strategy as Story 5.1 review F4).
|
|
62
|
+
#
|
|
63
|
+
# Coverage (Story 5.12 review F5 — broaden beyond curated list):
|
|
64
|
+
# - any <legacy>_<identifier> (catches private helpers),
|
|
65
|
+
# - any __<legacy>_<X>__ helper,
|
|
66
|
+
# - any __<UPPER>_<X>__ token format,
|
|
67
|
+
# - any data-<legacy> / data-<legacy>-<X> DOM attribute,
|
|
68
|
+
# - the [-:] router / suspense / doctor literals,
|
|
69
|
+
# - the legacy Request HTTP header,
|
|
70
|
+
# - the legacy lib/tasks/<legacy>.rake file path.
|
|
71
|
+
# Literals are intentionally written with placeholder text so this
|
|
72
|
+
# workflow file is itself grep-clean under its own regex.
|
|
73
|
+
run: |
|
|
74
|
+
R='rsc'
|
|
75
|
+
RU="$(printf '%s' "$R" | tr a-z A-Z)"
|
|
76
|
+
PATTERN="\\b(${R}_\\w+|__${R}_\\w+__|__${RU}_\\w*[0-9]+__|data-${R}(-\\w+|=)|${R}[-:](router|suspense|doctor)|${RU}-Request|lib/tasks/${R}\\.rake)\\b"
|
|
77
|
+
if git grep -nP "$PATTERN" -- \
|
|
78
|
+
':!CHANGELOG.md' \
|
|
79
|
+
':!doc/' \
|
|
80
|
+
':!*.gem' \
|
|
81
|
+
':!coverage/'; then
|
|
82
|
+
echo "::error::Residual rsc_* API reference found in gem source."
|
|
83
|
+
echo "::error::Rename to the ruact_* equivalent. See Story 5.12 in _bmad-output/implementation-artifacts/."
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
echo "::notice::No residual rsc_* API references found."
|
|
87
|
+
|
|
10
88
|
rspec:
|
|
11
89
|
# Required status check — all 8 matrix combinations must pass to merge.
|
|
12
90
|
name: RSpec (Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }})
|
|
@@ -18,30 +96,46 @@ jobs:
|
|
|
18
96
|
rails: ["7.0", "7.1", "7.2", "8.0"]
|
|
19
97
|
env:
|
|
20
98
|
RAILS_VERSION: ${{ matrix.rails }}
|
|
99
|
+
# The Gemfile injects `gem "rails", "~> #{ENV['RAILS_VERSION']}"` for
|
|
100
|
+
# matrix testing, but Gemfile.lock cannot pin all four Rails versions
|
|
101
|
+
# at once. `bundler-cache: true` defaults to deployment/frozen mode
|
|
102
|
+
# which rejects any Gemfile change vs lockfile, so disable that here
|
|
103
|
+
# while keeping the gem cache for everything else.
|
|
104
|
+
BUNDLE_DEPLOYMENT: "false"
|
|
105
|
+
BUNDLE_FROZEN: "false"
|
|
21
106
|
steps:
|
|
22
|
-
- uses: actions/checkout@
|
|
107
|
+
- uses: actions/checkout@v5
|
|
23
108
|
- uses: ruby/setup-ruby@v1
|
|
24
109
|
with:
|
|
25
110
|
ruby-version: ${{ matrix.ruby }}
|
|
26
111
|
bundler-cache: true
|
|
27
|
-
working-directory: gem
|
|
28
112
|
- name: Run RSpec
|
|
29
|
-
working-directory: gem
|
|
30
113
|
run: bundle exec rspec --format progress
|
|
114
|
+
- name: Upload coverage to Codecov
|
|
115
|
+
# Upload from one canonical matrix cell only (Ruby 3.3 × Rails 7.2)
|
|
116
|
+
# to avoid quota burn and Codecov-side flag merge conflicts. Other
|
|
117
|
+
# cells run RSpec but skip the upload. `success()` ensures we never
|
|
118
|
+
# upload partial/aborted runs. `fail_ci_if_error: false` keeps a
|
|
119
|
+
# Codecov outage from reddening a build whose tests passed.
|
|
120
|
+
if: matrix.ruby == '3.3' && matrix.rails == '7.2' && success()
|
|
121
|
+
uses: codecov/codecov-action@v5
|
|
122
|
+
with:
|
|
123
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
124
|
+
files: coverage/lcov.info
|
|
125
|
+
flags: gem
|
|
126
|
+
fail_ci_if_error: false
|
|
31
127
|
|
|
32
128
|
rubocop:
|
|
33
129
|
# Required status check.
|
|
34
130
|
name: RuboCop
|
|
35
131
|
runs-on: ubuntu-latest
|
|
36
132
|
steps:
|
|
37
|
-
- uses: actions/checkout@
|
|
133
|
+
- uses: actions/checkout@v5
|
|
38
134
|
- uses: ruby/setup-ruby@v1
|
|
39
135
|
with:
|
|
40
136
|
ruby-version: "3.3"
|
|
41
137
|
bundler-cache: true
|
|
42
|
-
working-directory: gem
|
|
43
138
|
- name: Run RuboCop
|
|
44
|
-
working-directory: gem
|
|
45
139
|
run: bundle exec rubocop --format github
|
|
46
140
|
|
|
47
141
|
yard:
|
|
@@ -49,14 +143,12 @@ jobs:
|
|
|
49
143
|
name: YARD Docs
|
|
50
144
|
runs-on: ubuntu-latest
|
|
51
145
|
steps:
|
|
52
|
-
- uses: actions/checkout@
|
|
146
|
+
- uses: actions/checkout@v5
|
|
53
147
|
- uses: ruby/setup-ruby@v1
|
|
54
148
|
with:
|
|
55
149
|
ruby-version: "3.3"
|
|
56
150
|
bundler-cache: true
|
|
57
|
-
working-directory: gem
|
|
58
151
|
- name: Validate YARD docs
|
|
59
|
-
working-directory: gem
|
|
60
152
|
run: bundle exec yard --fail-on-warning
|
|
61
153
|
|
|
62
154
|
benchmark:
|
|
@@ -64,103 +156,77 @@ jobs:
|
|
|
64
156
|
name: Memory Benchmark
|
|
65
157
|
runs-on: ubuntu-latest
|
|
66
158
|
steps:
|
|
67
|
-
- uses: actions/checkout@
|
|
159
|
+
- uses: actions/checkout@v5
|
|
68
160
|
- uses: ruby/setup-ruby@v1
|
|
69
161
|
with:
|
|
70
162
|
ruby-version: "3.3"
|
|
71
163
|
bundler-cache: true
|
|
72
|
-
working-directory: gem
|
|
73
164
|
- name: Run memory benchmark
|
|
74
|
-
working-directory: gem
|
|
75
165
|
run: bundle exec rake benchmark:memory
|
|
76
166
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
fail-fast: false
|
|
83
|
-
matrix:
|
|
84
|
-
react: ["19.0.0", "19.x"]
|
|
85
|
-
steps:
|
|
86
|
-
- uses: actions/checkout@v4
|
|
87
|
-
- uses: ruby/setup-ruby@v1
|
|
88
|
-
with:
|
|
89
|
-
ruby-version: "3.3"
|
|
90
|
-
bundler-cache: true
|
|
91
|
-
working-directory: e2e
|
|
92
|
-
- uses: actions/setup-node@v4
|
|
93
|
-
with:
|
|
94
|
-
node-version: "20"
|
|
95
|
-
- name: Install npm packages
|
|
96
|
-
working-directory: e2e
|
|
97
|
-
run: npm install
|
|
98
|
-
- name: Pin React version
|
|
99
|
-
working-directory: e2e
|
|
100
|
-
run: npm install react@${{ matrix.react }} react-dom@${{ matrix.react }}
|
|
101
|
-
- name: Build Vite assets
|
|
102
|
-
working-directory: e2e
|
|
103
|
-
run: npx vite build
|
|
104
|
-
- name: Run system tests
|
|
105
|
-
working-directory: e2e
|
|
106
|
-
env:
|
|
107
|
-
RAILS_ENV: test
|
|
108
|
-
run: bundle exec rails test:system
|
|
109
|
-
- name: Upload screenshots on failure
|
|
110
|
-
uses: actions/upload-artifact@v4
|
|
111
|
-
if: failure()
|
|
112
|
-
with:
|
|
113
|
-
name: e2e-screenshots-react-${{ matrix.react }}
|
|
114
|
-
path: e2e/tmp/screenshots
|
|
115
|
-
if-no-files-found: ignore
|
|
167
|
+
# E2E jobs (e2e and e2e-next) were removed from this workflow in Story 6.7.
|
|
168
|
+
# They depend on the `e2e/` Rails app in the planning monorepo and cannot run
|
|
169
|
+
# here (this repo has no `e2e/` directory). When/if a host-app system test
|
|
170
|
+
# is desired in CI, host the workflow in the monorepo (luizcg/ruact-dev) where
|
|
171
|
+
# both the gem submodule and the e2e/ Rails app live side by side.
|
|
116
172
|
|
|
117
|
-
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
|
|
173
|
+
release:
|
|
174
|
+
# Auto-release to RubyGems on every GREEN push to main, gated on the full
|
|
175
|
+
# required-check set via `needs:`. Versioning (source of truth:
|
|
176
|
+
# lib/ruact/version.rb): story verde -> patch; epic verde -> minor via an
|
|
177
|
+
# `[epic-done]` marker in the merge-commit message; major manual for 1.0.0.
|
|
178
|
+
# Auth is RubyGems Trusted Publishing (OIDC) — satisfies
|
|
179
|
+
# rubygems_mfa_required. The bump commit carries [skip ci] (no re-trigger).
|
|
180
|
+
name: Release to RubyGems
|
|
181
|
+
needs: [name-propagation, rspec, rubocop, yard, benchmark]
|
|
182
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
121
183
|
runs-on: ubuntu-latest
|
|
122
|
-
|
|
184
|
+
permissions:
|
|
185
|
+
id-token: write
|
|
186
|
+
contents: write
|
|
187
|
+
concurrency:
|
|
188
|
+
group: release
|
|
189
|
+
cancel-in-progress: false
|
|
123
190
|
steps:
|
|
124
|
-
- uses: actions/checkout@
|
|
191
|
+
- uses: actions/checkout@v5
|
|
192
|
+
with:
|
|
193
|
+
fetch-depth: 0
|
|
125
194
|
- uses: ruby/setup-ruby@v1
|
|
126
195
|
with:
|
|
127
196
|
ruby-version: "3.3"
|
|
128
197
|
bundler-cache: true
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
with:
|
|
132
|
-
node-version: "20"
|
|
133
|
-
- name: Install npm packages
|
|
134
|
-
working-directory: e2e
|
|
135
|
-
run: npm install
|
|
136
|
-
- name: Pin React@next
|
|
137
|
-
working-directory: e2e
|
|
138
|
-
run: npm install react@next react-dom@next
|
|
139
|
-
- name: Build Vite assets
|
|
140
|
-
working-directory: e2e
|
|
141
|
-
run: npx vite build
|
|
142
|
-
- name: Run system tests
|
|
143
|
-
id: system-tests
|
|
144
|
-
working-directory: e2e
|
|
198
|
+
- name: Decide bump kind & compute next version
|
|
199
|
+
id: bump
|
|
145
200
|
env:
|
|
146
|
-
|
|
147
|
-
run:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
201
|
+
HEAD_MSG: ${{ github.event.head_commit.message }}
|
|
202
|
+
run: |
|
|
203
|
+
KIND=patch
|
|
204
|
+
printf '%s' "$HEAD_MSG" | grep -qi '\[epic-done\]' && KIND=minor
|
|
205
|
+
VERSION=$(ruby -e '
|
|
206
|
+
kind = ARGV[0]
|
|
207
|
+
path = "lib/ruact/version.rb"
|
|
208
|
+
src = File.read(path)
|
|
209
|
+
maj, min, pat = src.match(/VERSION = "(\d+)\.(\d+)\.(\d+)"/).captures.map(&:to_i)
|
|
210
|
+
case kind
|
|
211
|
+
when "major" then maj, min, pat = maj + 1, 0, 0
|
|
212
|
+
when "minor" then min, pat = min + 1, 0
|
|
213
|
+
else pat += 1
|
|
214
|
+
end
|
|
215
|
+
v = "#{maj}.#{min}.#{pat}"
|
|
216
|
+
File.write(path, src.sub(/VERSION = "[^"]+"/, %(VERSION = "#{v}")))
|
|
217
|
+
print v
|
|
218
|
+
' "$KIND")
|
|
219
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
220
|
+
echo "::notice::Release bump $KIND -> v$VERSION"
|
|
221
|
+
- uses: rubygems/configure-rubygems-credentials@v2.0.0 # OIDC -> short-lived credential
|
|
222
|
+
- name: Commit, tag & publish
|
|
223
|
+
env:
|
|
224
|
+
VERSION: ${{ steps.bump.outputs.version }}
|
|
225
|
+
run: |
|
|
226
|
+
git config user.name "github-actions[bot]"
|
|
227
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
228
|
+
git commit -am "Release v$VERSION [skip ci]"
|
|
229
|
+
git tag "v$VERSION"
|
|
230
|
+
git push origin HEAD --tags
|
|
231
|
+
gem build ruact.gemspec
|
|
232
|
+
gem push "ruact-$VERSION.gem"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: Server-functions bench (AC12)
|
|
2
|
+
|
|
3
|
+
# Story 8.1 AC12 — non-blocking nightly perf guard. Runs the AR-backed
|
|
4
|
+
# end-to-end dispatch benchmark and posts the numbers as a workflow
|
|
5
|
+
# summary. Does NOT gate merge (the bench measures wall-clock and is
|
|
6
|
+
# subject to runner noise); it exists to surface 10× regressions in
|
|
7
|
+
# the open instead of after release.
|
|
8
|
+
#
|
|
9
|
+
# Triggers:
|
|
10
|
+
# - nightly cron (06:00 UTC)
|
|
11
|
+
# - PRs touching `lib/ruact/server_functions/**` or the bench script
|
|
12
|
+
# itself
|
|
13
|
+
# - manual `workflow_dispatch`
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
schedule:
|
|
17
|
+
- cron: "0 6 * * *"
|
|
18
|
+
pull_request:
|
|
19
|
+
paths:
|
|
20
|
+
- "lib/ruact/server_functions/**"
|
|
21
|
+
- "lib/ruact/controller.rb"
|
|
22
|
+
- "vendor/javascript/ruact-server-functions-runtime/**"
|
|
23
|
+
- "bench/server_functions_dispatch_bench.rb"
|
|
24
|
+
- ".github/workflows/server-functions-bench.yml"
|
|
25
|
+
workflow_dispatch:
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
bench:
|
|
29
|
+
name: Run dispatch bench
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
env:
|
|
32
|
+
BUNDLE_DEPLOYMENT: "false"
|
|
33
|
+
BUNDLE_FROZEN: "false"
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v5
|
|
36
|
+
- uses: ruby/setup-ruby@v1
|
|
37
|
+
with:
|
|
38
|
+
ruby-version: "3.3"
|
|
39
|
+
bundler-cache: true
|
|
40
|
+
- name: Run bench
|
|
41
|
+
id: bench
|
|
42
|
+
run: |
|
|
43
|
+
bundle exec ruby bench/server_functions_dispatch_bench.rb \
|
|
44
|
+
| tee bench-output.txt
|
|
45
|
+
- name: Post numbers as workflow summary
|
|
46
|
+
if: always()
|
|
47
|
+
run: |
|
|
48
|
+
{
|
|
49
|
+
echo "## Server-functions dispatch bench"
|
|
50
|
+
echo ""
|
|
51
|
+
echo '```'
|
|
52
|
+
cat bench-output.txt
|
|
53
|
+
echo '```'
|
|
54
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
data/.rubocop.yml
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
|
2
|
+
|
|
3
|
+
# Merge (union) Exclude arrays across .rubocop_todo.yml and this file —
|
|
4
|
+
# without this, a cop that declares its own Exclude below (e.g.
|
|
5
|
+
# Metrics/ModuleLength) would silently DISCARD the todo file's frozen
|
|
6
|
+
# exclusions for that cop (RuboCop's per-parameter override semantics).
|
|
7
|
+
inherit_mode:
|
|
8
|
+
merge:
|
|
9
|
+
- Exclude
|
|
10
|
+
|
|
1
11
|
require:
|
|
2
12
|
- rubocop/cop/ruact
|
|
3
13
|
|
|
@@ -31,6 +41,14 @@ Metrics/BlockLength:
|
|
|
31
41
|
Naming/VariableNumber:
|
|
32
42
|
Exclude:
|
|
33
43
|
- "lib/tasks/**/*.rake"
|
|
44
|
+
# Spec story-tag convention: `describe ..., :story_7_7` mirrors the story
|
|
45
|
+
# ID (7.7 → :story_7_7) so a single rspec invocation runs the regression
|
|
46
|
+
# suite for that story (project-context §11). Narrowed to the exact symbol
|
|
47
|
+
# shape rather than excluding all of spec/ — anything else under spec/ that
|
|
48
|
+
# tries to use snake_case-with-numbers still trips the cop. The optional
|
|
49
|
+
# trailing letter accommodates carve-out stories like 8.0a → :story_8_0a.
|
|
50
|
+
AllowedPatterns:
|
|
51
|
+
- '\bstory_\d+_\d+[a-z]?\b'
|
|
34
52
|
|
|
35
53
|
Metrics/ClassLength:
|
|
36
54
|
Max: 150
|
|
@@ -42,7 +60,7 @@ Metrics/ModuleLength:
|
|
|
42
60
|
|
|
43
61
|
Metrics/AbcSize:
|
|
44
62
|
Max: 50
|
|
45
|
-
# Note: PoC methods (
|
|
63
|
+
# Note: PoC methods (ruact_render, each, convert_element) will be refactored
|
|
46
64
|
# in later stories. Current values reflect tech debt, not design intent.
|
|
47
65
|
|
|
48
66
|
Metrics/CyclomaticComplexity:
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 100`
|
|
3
|
+
# on 2026-06-06 01:48:31 UTC using RuboCop version 1.85.1.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 2
|
|
10
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
11
|
+
# Configuration parameters: AllowAliasSyntax, AllowedMethods.
|
|
12
|
+
# AllowedMethods: alias_method, public, protected, private
|
|
13
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
|
14
|
+
Exclude:
|
|
15
|
+
- 'spec/ruact/server_functions/error_payload_spec.rb'
|
|
16
|
+
|
|
17
|
+
# Offense count: 14
|
|
18
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
19
|
+
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
|
|
20
|
+
# URISchemes: http, https
|
|
21
|
+
Layout/LineLength:
|
|
22
|
+
Exclude:
|
|
23
|
+
- 'bench/server_functions_dispatch_bench.rb'
|
|
24
|
+
- 'lib/ruact/errors.rb'
|
|
25
|
+
- 'lib/ruact/server_functions/error_suggestion.rb'
|
|
26
|
+
- 'spec/ruact/server_functions/endpoint_controller_rescue_spec.rb'
|
|
27
|
+
- 'spec/ruact/server_functions/error_suggestion_spec.rb'
|
|
28
|
+
- 'spec/ruact/server_functions/railtie_integration_spec.rb'
|
|
29
|
+
- 'spec/ruact/server_functions/snapshot_spec.rb'
|
|
30
|
+
|
|
31
|
+
# Offense count: 1
|
|
32
|
+
# Configuration parameters: AllowedMethods.
|
|
33
|
+
# AllowedMethods: enums
|
|
34
|
+
Lint/ConstantDefinitionInBlock:
|
|
35
|
+
Exclude:
|
|
36
|
+
- 'spec/ruact/server_functions/csrf_request_spec.rb'
|
|
37
|
+
|
|
38
|
+
# Offense count: 1
|
|
39
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
40
|
+
Metrics/AbcSize:
|
|
41
|
+
Exclude:
|
|
42
|
+
- 'lib/ruact/controller.rb'
|
|
43
|
+
|
|
44
|
+
# Offense count: 1
|
|
45
|
+
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
|
|
46
|
+
# AllowedMethods: refine
|
|
47
|
+
Metrics/BlockLength:
|
|
48
|
+
Exclude:
|
|
49
|
+
- 'lib/ruact/controller.rb'
|
|
50
|
+
|
|
51
|
+
# Offense count: 1
|
|
52
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
53
|
+
Metrics/CyclomaticComplexity:
|
|
54
|
+
Exclude:
|
|
55
|
+
- 'lib/ruact/controller.rb'
|
|
56
|
+
|
|
57
|
+
# Offense count: 2
|
|
58
|
+
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
59
|
+
Metrics/MethodLength:
|
|
60
|
+
Exclude:
|
|
61
|
+
- 'lib/ruact/controller.rb'
|
|
62
|
+
- 'lib/ruact/server_action.rb'
|
|
63
|
+
|
|
64
|
+
# Offense count: 2
|
|
65
|
+
# Configuration parameters: CountComments, Max, CountAsOne.
|
|
66
|
+
Metrics/ModuleLength:
|
|
67
|
+
Exclude:
|
|
68
|
+
- 'spec/**/*'
|
|
69
|
+
- 'lib/ruact/controller.rb'
|
|
70
|
+
- 'lib/ruact/server_functions/codegen.rb'
|
|
71
|
+
|
|
72
|
+
# Offense count: 1
|
|
73
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
74
|
+
Metrics/PerceivedComplexity:
|
|
75
|
+
Exclude:
|
|
76
|
+
- 'lib/ruact/controller.rb'
|
|
77
|
+
|
|
78
|
+
# Offense count: 1
|
|
79
|
+
RSpec/BeforeAfterAll:
|
|
80
|
+
Exclude:
|
|
81
|
+
- '**/spec/spec_helper.rb'
|
|
82
|
+
- '**/spec/rails_helper.rb'
|
|
83
|
+
- '**/spec/support/**/*.rb'
|
|
84
|
+
- 'spec/ruact/server_functions/dispatch_request_spec.rb'
|
|
85
|
+
|
|
86
|
+
# Offense count: 1
|
|
87
|
+
# Configuration parameters: Prefixes, AllowedPatterns.
|
|
88
|
+
# Prefixes: when, with, without
|
|
89
|
+
RSpec/ContextWording:
|
|
90
|
+
Exclude:
|
|
91
|
+
- 'spec/ruact/controller_spec.rb'
|
|
92
|
+
|
|
93
|
+
# Offense count: 2
|
|
94
|
+
RSpec/LeakyConstantDeclaration:
|
|
95
|
+
Exclude:
|
|
96
|
+
- 'spec/ruact/server_functions/csrf_request_spec.rb'
|
|
97
|
+
|
|
98
|
+
# Offense count: 1
|
|
99
|
+
# Configuration parameters: EnforcedStyle.
|
|
100
|
+
# SupportedStyles: have_received, receive
|
|
101
|
+
RSpec/MessageSpies:
|
|
102
|
+
Exclude:
|
|
103
|
+
- 'spec/ruact/server_functions/railtie_integration_spec.rb'
|
|
104
|
+
|
|
105
|
+
# Offense count: 5
|
|
106
|
+
# Configuration parameters: Max.
|
|
107
|
+
RSpec/MultipleExpectations:
|
|
108
|
+
Exclude:
|
|
109
|
+
- 'spec/ruact/controller_spec.rb'
|
|
110
|
+
- 'spec/ruact/server_functions/csrf_request_spec.rb'
|
|
111
|
+
- 'spec/ruact/server_functions/endpoint_controller_rescue_spec.rb'
|
|
112
|
+
- 'spec/ruact/server_functions/standalone_action_spec.rb'
|
|
113
|
+
|
|
114
|
+
# Offense count: 2
|
|
115
|
+
RSpec/RemoveConst:
|
|
116
|
+
Exclude:
|
|
117
|
+
- 'spec/ruact/server_functions/railtie_integration_spec.rb'
|
|
118
|
+
|
|
119
|
+
# Offense count: 1
|
|
120
|
+
# Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
|
|
121
|
+
# SupportedInflectors: default, active_support
|
|
122
|
+
RSpec/SpecFilePathFormat:
|
|
123
|
+
Exclude:
|
|
124
|
+
- '**/spec/routing/**/*'
|
|
125
|
+
- 'spec/ruact/server_functions/standalone_action_spec.rb'
|
|
126
|
+
|
|
127
|
+
# Offense count: 3
|
|
128
|
+
Ruact/NoSharedState:
|
|
129
|
+
Exclude:
|
|
130
|
+
- 'lib/ruact/controller.rb'
|
|
131
|
+
- 'lib/ruact/server_functions/endpoint_controller.rb'
|
|
132
|
+
|
|
133
|
+
# Offense count: 2
|
|
134
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
135
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
|
136
|
+
# AllowedMethods: ==, equal?, eql?
|
|
137
|
+
Style/ClassEqualityComparison:
|
|
138
|
+
Exclude:
|
|
139
|
+
- 'lib/ruact/server_functions/error_payload.rb'
|
|
140
|
+
|
|
141
|
+
# Offense count: 1
|
|
142
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
143
|
+
Style/IfUnlessModifier:
|
|
144
|
+
Exclude:
|
|
145
|
+
- 'bench/server_functions_dispatch_bench.rb'
|
|
146
|
+
|
|
147
|
+
# Offense count: 1
|
|
148
|
+
Style/MixinUsage:
|
|
149
|
+
Exclude:
|
|
150
|
+
- 'bench/server_functions_dispatch_bench.rb'
|
|
151
|
+
|
|
152
|
+
# Offense count: 7
|
|
153
|
+
Style/MultilineBlockChain:
|
|
154
|
+
Exclude:
|
|
155
|
+
- 'spec/ruact/server_functions/registry_spec.rb'
|
|
156
|
+
- 'spec/ruact/server_functions/standalone_action_spec.rb'
|
|
157
|
+
|
|
158
|
+
# Offense count: 5
|
|
159
|
+
# Configuration parameters: AllowedClasses.
|
|
160
|
+
Style/OneClassPerFile:
|
|
161
|
+
Exclude:
|
|
162
|
+
- 'bench/server_functions_dispatch_bench.rb'
|
|
163
|
+
- 'spec/ruact/server_functions/csrf_request_spec.rb'
|
|
164
|
+
|
|
165
|
+
# Offense count: 2
|
|
166
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
167
|
+
Style/RedundantFreeze:
|
|
168
|
+
Exclude:
|
|
169
|
+
- 'spec/ruact/server_functions/error_payload_spec.rb'
|
|
170
|
+
|
|
171
|
+
# Offense count: 1
|
|
172
|
+
# Configuration parameters: Max.
|
|
173
|
+
Style/SafeNavigationChainLength:
|
|
174
|
+
Exclude:
|
|
175
|
+
- 'lib/ruact/server_functions/standalone_dispatcher.rb'
|