Skip to content

Commit 93ab331

Browse files
Merge pull request #10 from fabienpiette/feat/rails-filters
feat(filters): add Rails ecosystem filters
2 parents 7bde5b6 + ab68505 commit 93ab331

File tree

9 files changed

+287
-0
lines changed

9 files changed

+287
-0
lines changed

filters/bundle-install.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: "bundle-install"
2+
version: 1
3+
description: "Condensed bundle install output"
4+
5+
match:
6+
command: "bundle"
7+
subcommand: "install"
8+
9+
pipeline:
10+
- action: "keep_lines"
11+
pattern: "\\S"
12+
- action: "aggregate"
13+
patterns:
14+
installed: "^Installing "
15+
using: "^Using "
16+
fetching: "^Fetching "
17+
complete: "^Bundle complete"
18+
format: "Bundle complete ({{.using}} cached, {{.installed}} installed)"
19+
20+
on_error: "passthrough"

filters/rails-migrate.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: "rails-migrate"
2+
version: 1
3+
description: "Condensed rails db:migrate output"
4+
5+
match:
6+
command: "rails"
7+
subcommand: "db:migrate"
8+
9+
pipeline:
10+
- action: "keep_lines"
11+
pattern: "\\S"
12+
- action: "remove_lines"
13+
pattern: "^\\s*(-|->)"
14+
- action: "keep_lines"
15+
pattern: "migrated"
16+
- action: "regex_extract"
17+
pattern: "== \\d+ (\\w+): migrated"
18+
format: "- $1"
19+
- action: "aggregate"
20+
patterns:
21+
migrated: "^-"
22+
- action: "format_template"
23+
template: "{{with .stats}}{{.migrated}} migrations executed:{{end}}\n{{.lines}}"
24+
25+
on_error: "passthrough"

filters/rails-routes.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: "rails-routes"
2+
version: 1
3+
description: "Summarized rails routes with count and truncation"
4+
5+
match:
6+
command: "rails"
7+
subcommand: "routes"
8+
exclude_flags: ["-g", "--grep", "-c", "--controller"]
9+
10+
pipeline:
11+
- action: "keep_lines"
12+
pattern: "\\S"
13+
- action: "remove_lines"
14+
pattern: "^\\s*Prefix"
15+
- action: "aggregate"
16+
patterns:
17+
routes: "(GET|POST|PUT|PATCH|DELETE)"
18+
- action: "head"
19+
n: 15
20+
- action: "format_template"
21+
template: "{{with .stats}}{{.routes}} routes total{{end}} (showing first 15):\n{{.lines}}"
22+
23+
on_error: "passthrough"

filters/rspec.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: "rspec"
2+
version: 1
3+
description: "Condensed RSpec output with pass/fail summary"
4+
5+
match:
6+
command: "rspec"
7+
exclude_flags: ["--format", "-f"]
8+
9+
pipeline:
10+
- action: "keep_lines"
11+
pattern: "\\S"
12+
- action: "keep_lines"
13+
pattern: "(^\\d+ examples|^rspec \\./)"
14+
- action: "head"
15+
n: 10
16+
17+
on_error: "passthrough"

internal/filter/actions_integration_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,36 @@ func TestCargoTestFilterIntegration(t *testing.T) {
215215
}
216216
}
217217

218+
func TestRSpecFilterIntegration(t *testing.T) {
219+
fixture := loadFixture(t, "rspec_raw.txt")
220+
f := loadFilter(t, "rspec.yaml")
221+
222+
filtered, err := applyPipeline(f, fixture)
223+
if err != nil {
224+
t.Fatalf("apply pipeline: %v", err)
225+
}
226+
227+
// Should be much shorter
228+
if len(filtered) >= len(fixture) {
229+
t.Errorf("filtered (%d) not shorter than input (%d)", len(filtered), len(fixture))
230+
}
231+
232+
// Should contain summary
233+
if !strings.Contains(filtered, "examples") {
234+
t.Error("filtered output missing examples count")
235+
}
236+
237+
// Should preserve failure paths (essential for debugging)
238+
if strings.Contains(fixture, "rspec ./") && !strings.Contains(filtered, "rspec ./") {
239+
t.Error("filtered output missing failure paths (rspec ./spec/...)")
240+
}
241+
242+
inputTokens := utils.EstimateTokens(fixture)
243+
outputTokens := utils.EstimateTokens(filtered)
244+
savings := float64(inputTokens-outputTokens) / float64(inputTokens) * 100
245+
t.Logf("rspec: %d -> %d tokens (%.1f%% savings)", inputTokens, outputTokens, savings)
246+
}
247+
218248
// Edge case tests
219249
func TestFilterEmptyInput(t *testing.T) {
220250
f := loadFilter(t, "git-log.yaml")
@@ -256,6 +286,82 @@ func TestFilterANSIInput(t *testing.T) {
256286
}
257287
}
258288

289+
func TestBundleInstallFilterIntegration(t *testing.T) {
290+
fixture := loadFixture(t, "bundle_install_raw.txt")
291+
f := loadFilter(t, "bundle-install.yaml")
292+
293+
filtered, err := applyPipeline(f, fixture)
294+
if err != nil {
295+
t.Fatalf("apply pipeline: %v", err)
296+
}
297+
298+
if len(filtered) >= len(fixture) {
299+
t.Errorf("filtered (%d) not shorter than input (%d)", len(filtered), len(fixture))
300+
}
301+
302+
if !strings.Contains(filtered, "Bundle complete") {
303+
t.Error("filtered output missing Bundle complete")
304+
}
305+
306+
// Calculate and log token savings
307+
inputTokens := utils.EstimateTokens(fixture)
308+
outputTokens := utils.EstimateTokens(filtered)
309+
savings := float64(inputTokens-outputTokens) / float64(inputTokens) * 100
310+
t.Logf("bundle-install: %d -> %d tokens (%.1f%% savings)", inputTokens, outputTokens, savings)
311+
}
312+
313+
func TestRailsRoutesFilterIntegration(t *testing.T) {
314+
fixture := loadFixture(t, "rails_routes_raw.txt")
315+
f := loadFilter(t, "rails-routes.yaml")
316+
317+
filtered, err := applyPipeline(f, fixture)
318+
if err != nil {
319+
t.Fatalf("apply pipeline: %v", err)
320+
}
321+
322+
// Should be shorter
323+
if len(filtered) >= len(fixture) {
324+
t.Errorf("filtered (%d) not shorter than input (%d)", len(filtered), len(fixture))
325+
}
326+
327+
// Should contain routes total summary
328+
if !strings.Contains(filtered, "routes total") {
329+
t.Error("filtered output missing 'routes total'")
330+
}
331+
332+
// Calculate and log token savings
333+
inputTokens := utils.EstimateTokens(fixture)
334+
outputTokens := utils.EstimateTokens(filtered)
335+
savings := float64(inputTokens-outputTokens) / float64(inputTokens) * 100
336+
t.Logf("rails-routes: %d -> %d tokens (%.1f%% savings)", inputTokens, outputTokens, savings)
337+
}
338+
339+
func TestRailsMigrateFilterIntegration(t *testing.T) {
340+
fixture := loadFixture(t, "rails_migrate_raw.txt")
341+
f := loadFilter(t, "rails-migrate.yaml")
342+
343+
filtered, err := applyPipeline(f, fixture)
344+
if err != nil {
345+
t.Fatalf("apply pipeline: %v", err)
346+
}
347+
348+
// Should be shorter
349+
if len(filtered) >= len(fixture) {
350+
t.Errorf("filtered (%d) not shorter than input (%d)", len(filtered), len(fixture))
351+
}
352+
353+
// Should contain migrations executed summary
354+
if !strings.Contains(filtered, "migrations executed") {
355+
t.Error("filtered output missing 'migrations executed'")
356+
}
357+
358+
// Calculate and log token savings
359+
inputTokens := utils.EstimateTokens(fixture)
360+
outputTokens := utils.EstimateTokens(filtered)
361+
savings := float64(inputTokens-outputTokens) / float64(inputTokens) * 100
362+
t.Logf("rails-migrate: %d -> %d tokens (%.1f%% savings)", inputTokens, outputTokens, savings)
363+
}
364+
259365
func TestGracefulDegradation(t *testing.T) {
260366
// Bad filter YAML
261367
badYAML := `
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Fetching gem metadata from https://rubygems.org/...........
2+
Resolving dependencies...
3+
Using rake 13.0.6
4+
Using concurrent-ruby 1.2.2
5+
Using i18n 1.14.1
6+
Fetching minitest 5.20.0
7+
Installing minitest 5.20.0
8+
Using tzinfo 2.0.6
9+
Using activesupport 7.1.2
10+
Fetching nokogiri 1.15.4 (x86_64-linux)
11+
Installing nokogiri 1.15.4 (x86_64-linux)
12+
Using rack 3.0.8
13+
Using rack-test 2.1.0
14+
Using erubi 1.12.0
15+
Using rails-dom-testing 2.2.0
16+
Using rails-html-sanitizer 1.6.0
17+
Using actionview 7.1.2
18+
Using actionpack 7.1.2
19+
Fetching puma 6.4.0
20+
Installing puma 6.4.0 with native extensions
21+
Using railties 7.1.2
22+
Using sprockets 4.2.1
23+
Using sprockets-rails 3.4.2
24+
Using rails 7.1.2
25+
Bundle complete! 15 Gemfile dependencies, 78 gems now installed.
26+
Use `bundle info [gemname]` to see where a bundled gem is installed.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
== 20240115123456 CreateUsers: migrating ======================================
2+
-- create_table(:users)
3+
-> 0.0234s
4+
== 20240115123456 CreateUsers: migrated (0.0235s) =============================
5+
6+
== 20240116789012 AddIndexToOrders: migrating =================================
7+
-- add_index(:orders, :user_id)
8+
-> 0.0123s
9+
== 20240116789012 AddIndexToOrders: migrated (0.0124s) ========================
10+
11+
== 20240117111111 CreateProducts: migrating ===================================
12+
-- create_table(:products)
13+
-> 0.0456s
14+
-- add_index(:products, :category_id)
15+
-> 0.0078s
16+
== 20240117111111 CreateProducts: migrated (0.0534s) ==========================
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
Prefix Verb URI Pattern Controller#Action
2+
root GET / home#index
3+
users GET /users(.:format) users#index
4+
POST /users(.:format) users#create
5+
new_user GET /users/new(.:format) users#new
6+
edit_user GET /users/:id/edit(.:format) users#edit
7+
user GET /users/:id(.:format) users#show
8+
PATCH /users/:id(.:format) users#update
9+
PUT /users/:id(.:format) users#update
10+
DELETE /users/:id(.:format) users#destroy
11+
orders GET /orders(.:format) orders#index
12+
POST /orders(.:format) orders#create
13+
new_order GET /orders/new(.:format) orders#new
14+
edit_order GET /orders/:id/edit(.:format) orders#edit
15+
order GET /orders/:id(.:format) orders#show
16+
PATCH /orders/:id(.:format) orders#update
17+
PUT /orders/:id(.:format) orders#update
18+
DELETE /orders/:id(.:format) orders#destroy
19+
products GET /products(.:format) products#index
20+
POST /products(.:format) products#create
21+
new_product GET /products/new(.:format) products#new
22+
edit_product GET /products/:id/edit(.:format) products#edit
23+
product GET /products/:id(.:format) products#show
24+
PATCH /products/:id(.:format) products#update
25+
PUT /products/:id(.:format) products#update
26+
DELETE /products/:id(.:format) products#destroy
27+
categories GET /categories(.:format) categories#index
28+
POST /categories(.:format) categories#create

tests/fixtures/rspec_raw.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Randomized with seed 12345
2+
3+
UserController
4+
GET /users
5+
returns a list of users
6+
POST /users
7+
creates a new user
8+
with invalid params
9+
returns errors
10+
11+
OrderService
12+
#process
13+
with valid order
14+
processes payment
15+
sends confirmation email
16+
with invalid order
17+
raises error
18+
19+
Finished in 0.45623 seconds (files took 1.23 seconds to load)
20+
42 examples, 3 failures, 2 pending
21+
22+
Failed examples:
23+
24+
rspec ./spec/controllers/users_controller_spec.rb:25 # UserController POST /users with invalid params returns errors
25+
rspec ./spec/services/order_service_spec.rb:45 # OrderService #process with invalid order raises error
26+
rspec ./spec/services/order_service_spec.rb:52 # OrderService #process with invalid order logs error

0 commit comments

Comments
 (0)