crspec 0.1.1 → 0.1.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.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -0
  3. data/README.md +1 -1
  4. data/lib/crspec/cli.rb +86 -5
  5. data/lib/crspec/configuration.rb +62 -9
  6. data/lib/crspec/dsl.rb +66 -2
  7. data/lib/crspec/example.rb +60 -6
  8. data/lib/crspec/example_group.rb +363 -63
  9. data/lib/crspec/execution_context.rb +10 -6
  10. data/lib/crspec/expectations.rb +62 -2
  11. data/lib/crspec/file_fixtures.rb +18 -0
  12. data/lib/crspec/formatters/progress_formatter.rb +37 -14
  13. data/lib/crspec/matchers.rb +642 -0
  14. data/lib/crspec/mock/argument_matchers.rb +157 -0
  15. data/lib/crspec/mock/double.rb +246 -13
  16. data/lib/crspec/mock/interceptor.rb +32 -9
  17. data/lib/crspec/mock/space.rb +14 -0
  18. data/lib/crspec/process_runner.rb +332 -0
  19. data/lib/crspec/rails/assets_shim.rb +33 -0
  20. data/lib/crspec/rails/database_isolation.rb +179 -8
  21. data/lib/crspec/rails/parallel.rb +29 -29
  22. data/lib/crspec/rails/request_helpers.rb +70 -14
  23. data/lib/crspec/rails/system_server.rb +7 -0
  24. data/lib/crspec/rails/warden_shim.rb +18 -0
  25. data/lib/crspec/runner.rb +143 -29
  26. data/lib/crspec/shared_examples.rb +70 -0
  27. data/lib/crspec/status_persistence.rb +46 -0
  28. data/lib/crspec/transpiler/cli.rb +106 -15
  29. data/lib/crspec/transpiler/rewriter.rb +179 -25
  30. data/lib/crspec/version.rb +1 -1
  31. data/lib/crspec.rb +6 -0
  32. data/lib/rspec/core.rb +2 -0
  33. data/lib/rspec/expectations.rb +2 -0
  34. data/lib/rspec/mocks.rb +2 -0
  35. data/lib/rspec/rails.rb +2 -0
  36. data/lib/rspec.rb +2 -0
  37. metadata +27 -156
  38. data/benchmark/README.md +0 -56
  39. data/benchmark/run.rb +0 -72
  40. data/benchmark/spec/user_service_crspec_spec.rb +0 -15
  41. data/benchmark/spec/user_service_rspec_spec.rb +0 -16
  42. data/benchmark/target_service.rb +0 -12
  43. data/benchmark/test/user_service_test.rb +0 -18
  44. data/demo.rb +0 -129
  45. data/samples/book_store/.dockerignore +0 -51
  46. data/samples/book_store/.gitattributes +0 -9
  47. data/samples/book_store/.github/dependabot.yml +0 -12
  48. data/samples/book_store/.github/workflows/ci.yml +0 -130
  49. data/samples/book_store/.gitignore +0 -35
  50. data/samples/book_store/.kamal/hooks/docker-setup.sample +0 -3
  51. data/samples/book_store/.kamal/hooks/post-app-boot.sample +0 -3
  52. data/samples/book_store/.kamal/hooks/post-deploy.sample +0 -14
  53. data/samples/book_store/.kamal/hooks/post-proxy-reboot.sample +0 -3
  54. data/samples/book_store/.kamal/hooks/pre-app-boot.sample +0 -3
  55. data/samples/book_store/.kamal/hooks/pre-build.sample +0 -51
  56. data/samples/book_store/.kamal/hooks/pre-connect.sample +0 -47
  57. data/samples/book_store/.kamal/hooks/pre-deploy.sample +0 -122
  58. data/samples/book_store/.kamal/hooks/pre-proxy-reboot.sample +0 -3
  59. data/samples/book_store/.kamal/secrets +0 -20
  60. data/samples/book_store/.rubocop.yml +0 -8
  61. data/samples/book_store/.ruby-version +0 -1
  62. data/samples/book_store/Dockerfile +0 -77
  63. data/samples/book_store/Gemfile +0 -67
  64. data/samples/book_store/Gemfile.lock +0 -572
  65. data/samples/book_store/README.md +0 -24
  66. data/samples/book_store/Rakefile +0 -6
  67. data/samples/book_store/app/assets/images/.keep +0 -0
  68. data/samples/book_store/app/assets/stylesheets/application.css +0 -10
  69. data/samples/book_store/app/controllers/application_controller.rb +0 -2
  70. data/samples/book_store/app/controllers/books_controller.rb +0 -30
  71. data/samples/book_store/app/controllers/comments_controller.rb +0 -21
  72. data/samples/book_store/app/controllers/concerns/.keep +0 -0
  73. data/samples/book_store/app/controllers/users_controller.rb +0 -21
  74. data/samples/book_store/app/helpers/application_helper.rb +0 -2
  75. data/samples/book_store/app/helpers/books_helper.rb +0 -2
  76. data/samples/book_store/app/helpers/comments_helper.rb +0 -2
  77. data/samples/book_store/app/helpers/users_helper.rb +0 -2
  78. data/samples/book_store/app/javascript/application.js +0 -3
  79. data/samples/book_store/app/javascript/controllers/application.js +0 -9
  80. data/samples/book_store/app/javascript/controllers/hello_controller.js +0 -7
  81. data/samples/book_store/app/javascript/controllers/index.js +0 -4
  82. data/samples/book_store/app/jobs/application_job.rb +0 -7
  83. data/samples/book_store/app/mailers/application_mailer.rb +0 -4
  84. data/samples/book_store/app/models/application_record.rb +0 -3
  85. data/samples/book_store/app/models/book.rb +0 -10
  86. data/samples/book_store/app/models/comment.rb +0 -6
  87. data/samples/book_store/app/models/concerns/.keep +0 -0
  88. data/samples/book_store/app/models/user.rb +0 -4
  89. data/samples/book_store/app/views/layouts/application.html.erb +0 -29
  90. data/samples/book_store/app/views/layouts/mailer.html.erb +0 -13
  91. data/samples/book_store/app/views/layouts/mailer.text.erb +0 -1
  92. data/samples/book_store/app/views/pwa/manifest.json.erb +0 -22
  93. data/samples/book_store/app/views/pwa/service-worker.js +0 -26
  94. data/samples/book_store/bin/brakeman +0 -7
  95. data/samples/book_store/bin/bundler-audit +0 -6
  96. data/samples/book_store/bin/ci +0 -6
  97. data/samples/book_store/bin/dev +0 -2
  98. data/samples/book_store/bin/docker-entrypoint +0 -8
  99. data/samples/book_store/bin/importmap +0 -4
  100. data/samples/book_store/bin/jobs +0 -6
  101. data/samples/book_store/bin/kamal +0 -16
  102. data/samples/book_store/bin/rails +0 -4
  103. data/samples/book_store/bin/rake +0 -4
  104. data/samples/book_store/bin/rubocop +0 -8
  105. data/samples/book_store/bin/setup +0 -35
  106. data/samples/book_store/bin/thrust +0 -5
  107. data/samples/book_store/config/application.rb +0 -27
  108. data/samples/book_store/config/boot.rb +0 -4
  109. data/samples/book_store/config/bundler-audit.yml +0 -5
  110. data/samples/book_store/config/cable.yml +0 -17
  111. data/samples/book_store/config/cache.yml +0 -16
  112. data/samples/book_store/config/ci.rb +0 -24
  113. data/samples/book_store/config/credentials.yml.enc +0 -1
  114. data/samples/book_store/config/database.yml +0 -45
  115. data/samples/book_store/config/deploy.yml +0 -119
  116. data/samples/book_store/config/environment.rb +0 -5
  117. data/samples/book_store/config/environments/development.rb +0 -78
  118. data/samples/book_store/config/environments/production.rb +0 -90
  119. data/samples/book_store/config/environments/test.rb +0 -53
  120. data/samples/book_store/config/importmap.rb +0 -7
  121. data/samples/book_store/config/initializers/assets.rb +0 -7
  122. data/samples/book_store/config/initializers/content_security_policy.rb +0 -29
  123. data/samples/book_store/config/initializers/filter_parameter_logging.rb +0 -8
  124. data/samples/book_store/config/initializers/inflections.rb +0 -16
  125. data/samples/book_store/config/locales/en.yml +0 -31
  126. data/samples/book_store/config/puma.rb +0 -42
  127. data/samples/book_store/config/queue.yml +0 -18
  128. data/samples/book_store/config/recurring.yml +0 -15
  129. data/samples/book_store/config/routes.rb +0 -17
  130. data/samples/book_store/config/storage.yml +0 -27
  131. data/samples/book_store/config.ru +0 -6
  132. data/samples/book_store/db/cable_schema.rb +0 -11
  133. data/samples/book_store/db/cache_schema.rb +0 -12
  134. data/samples/book_store/db/migrate/20260731035441_create_users.rb +0 -10
  135. data/samples/book_store/db/migrate/20260731035506_create_books.rb +0 -11
  136. data/samples/book_store/db/migrate/20260731035528_create_comments.rb +0 -11
  137. data/samples/book_store/db/queue_schema.rb +0 -129
  138. data/samples/book_store/db/schema.rb +0 -39
  139. data/samples/book_store/db/seeds.rb +0 -9
  140. data/samples/book_store/lib/tasks/.keep +0 -0
  141. data/samples/book_store/log/.keep +0 -0
  142. data/samples/book_store/public/400.html +0 -135
  143. data/samples/book_store/public/404.html +0 -135
  144. data/samples/book_store/public/406-unsupported-browser.html +0 -135
  145. data/samples/book_store/public/422.html +0 -135
  146. data/samples/book_store/public/500.html +0 -135
  147. data/samples/book_store/public/icon.png +0 -0
  148. data/samples/book_store/public/icon.svg +0 -3
  149. data/samples/book_store/public/robots.txt +0 -1
  150. data/samples/book_store/script/.keep +0 -0
  151. data/samples/book_store/spec/models/book_spec.rb +0 -42
  152. data/samples/book_store/spec/models/comment_spec.rb +0 -22
  153. data/samples/book_store/spec/models/user_advanced_spec.rb +0 -27
  154. data/samples/book_store/spec/models/user_spec.rb +0 -30
  155. data/samples/book_store/spec/rails_helper.rb +0 -36
  156. data/samples/book_store/spec/rails_parallel_spec.rb +0 -23
  157. data/samples/book_store/spec/requests/books_spec.rb +0 -21
  158. data/samples/book_store/spec/requests/users_spec.rb +0 -14
  159. data/samples/book_store/spec/services/inventory_service_spec.rb +0 -28
  160. data/samples/book_store/spec/services/time_dependent_service_spec.rb +0 -26
  161. data/samples/book_store/spec/spec_helper.rb +0 -16
  162. data/samples/book_store/spec/system/book_store_system_spec.rb +0 -18
  163. data/samples/book_store/storage/.keep +0 -0
  164. data/samples/book_store/test/controllers/.keep +0 -0
  165. data/samples/book_store/test/controllers/books_controller_test.rb +0 -7
  166. data/samples/book_store/test/controllers/comments_controller_test.rb +0 -7
  167. data/samples/book_store/test/controllers/users_controller_test.rb +0 -7
  168. data/samples/book_store/test/fixtures/books.yml +0 -11
  169. data/samples/book_store/test/fixtures/comments.yml +0 -11
  170. data/samples/book_store/test/fixtures/files/.keep +0 -0
  171. data/samples/book_store/test/fixtures/users.yml +0 -9
  172. data/samples/book_store/test/helpers/.keep +0 -0
  173. data/samples/book_store/test/integration/.keep +0 -0
  174. data/samples/book_store/test/mailers/.keep +0 -0
  175. data/samples/book_store/test/models/.keep +0 -0
  176. data/samples/book_store/test/models/book_test.rb +0 -7
  177. data/samples/book_store/test/models/comment_test.rb +0 -7
  178. data/samples/book_store/test/models/user_test.rb +0 -7
  179. data/samples/book_store/test/test_helper.rb +0 -15
  180. data/samples/book_store/tmp/.keep +0 -0
  181. data/samples/book_store/tmp/pids/.keep +0 -0
  182. data/samples/book_store/tmp/storage/.keep +0 -0
  183. data/samples/book_store/vendor/.keep +0 -0
  184. data/samples/book_store/vendor/javascript/.keep +0 -0
  185. data/samples/user_spec.rb +0 -31
  186. data/test/crspec/configuration_test.rb +0 -76
  187. data/test/crspec/execution_context_test.rb +0 -61
  188. data/test/crspec/mock_test.rb +0 -55
  189. data/test/crspec/rails_test.rb +0 -62
  190. data/test/crspec/runner_test.rb +0 -68
  191. data/test/crspec/transpiler_test.rb +0 -41
  192. data/test/test_helper.rb +0 -6
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "digest"
4
-
5
- class UserService
6
- def self.process_user(id, name, email)
7
- # Simulate non-blocking I/O query (e.g. database lease / HTTP call)
8
- sleep 0.001
9
- token = Digest::SHA256.hexdigest("#{id}-#{name}-#{email}")
10
- { id: id, name: name, email: email, token: token, valid: true }
11
- end
12
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "minitest"
4
- require_relative "../target_service"
5
-
6
- Minitest.seed ||= srand
7
-
8
- class UserServiceTest < Minitest::Test
9
- parallelize_me! if respond_to?(:parallelize_me!)
10
-
11
- 100.times do |i|
12
- define_method(:"test_user_#{i}") do
13
- u = UserService.process_user(i, "User #{i}", "user#{i}@example.com")
14
- assert u[:valid]
15
- refute_nil u[:token]
16
- end
17
- end
18
- end
data/demo.rb DELETED
@@ -1,129 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/inline"
4
-
5
- gemfile do
6
- source "https://rubygems.org"
7
- gem "crspec", path: __dir__
8
- gem "prism"
9
- gem "rails", "~> 8.0"
10
- gem "sqlite3"
11
- end
12
-
13
- require "crspec"
14
- require "rails"
15
-
16
- puts "================================================================="
17
- puts " Crspec Single-File Inline Demo & Feature Verification "
18
- puts "================================================================="
19
-
20
- # Reset global state for clean standalone run
21
- Crspec.reset!
22
-
23
- # Domain Models
24
- class User
25
- attr_accessor :name, :email
26
-
27
- def initialize(name:, email:)
28
- @name = name
29
- @email = email
30
- end
31
-
32
- def valid?
33
- return false if name.nil? || email.nil?
34
-
35
- email.include?("@")
36
- end
37
- end
38
-
39
- class PaymentProcessor
40
- def charge(amount)
41
- "real_charge_#{amount}"
42
- end
43
- end
44
-
45
- # 1. Core DSL, Context Isolation, Lazy Let Memoization, Matchers
46
- Crspec.describe User, type: :model do
47
- let(:valid_attributes) { { name: "Jane Doe", email: "jane@example.com" } }
48
- subject(:user) { User.new(**valid_attributes) }
49
-
50
- before do
51
- # Per-example setup hook
52
- end
53
-
54
- it "validates primary attributes concurrently" do
55
- expect(user.valid?).to be(true)
56
- expect(user.name).to eq("Jane Doe")
57
- expect(user.email).to include("example.com")
58
- end
59
-
60
- context "when email is invalid" do
61
- let(:valid_attributes) { { name: "Jane Doe", email: nil } }
62
-
63
- it "flags validation errors" do
64
- expect(user.valid?).to eq(false)
65
- end
66
- end
67
-
68
- context "when error is expected" do
69
- it "catches raised exceptions" do
70
- expect { raise ArgumentError, "Invalid user input" }.to raise_error(ArgumentError, "Invalid user input")
71
- end
72
- end
73
- end
74
-
75
- # 2. Fiber-Aware Mocking Engine (crspec-mock)
76
- Crspec.describe PaymentProcessor do
77
- let(:processor) { PaymentProcessor.new }
78
-
79
- it "supports fiber-isolated method stubs" do
80
- allow(processor).to receive(:charge).with(5000).and_return("succeeded")
81
- expect(processor.charge(5000)).to eq("succeeded")
82
- end
83
-
84
- it "supports test doubles and method expectations" do
85
- gateway_double = double("StripeGateway", process: "ok")
86
- expect(gateway_double.process).to eq("ok")
87
- end
88
- end
89
-
90
- # 3. Rails Parallel Worker Integration (crspec-rails)
91
- Crspec::Rails::Parallel.parallelize(workers: 4) do
92
- parallelize_setup do |_worker_num|
93
- # Per-worker setup hook
94
- end
95
-
96
- parallelize_teardown do |_worker_num|
97
- # Per-worker teardown hook
98
- end
99
- end
100
-
101
- # 4. Prism AST Transpiler Verification (crspec-transpiler)
102
- rspec_sample_code = <<~RUBY
103
- RSpec.describe "Legacy Suite" do
104
- it "runs" do
105
- expect(1).to eq(1)
106
- end
107
- end
108
- RUBY
109
-
110
- transpiled = Crspec::Transpiler::Rewriter.new(rspec_sample_code).transpile
111
- puts "[Prism Transpiler Check] RSpec -> Crspec: #{transpiled.include?("Crspec.describe") ? "PASSED" : "FAILED"}"
112
-
113
- # 5. Concurrent Multi-Threaded Execution Kernel
114
- puts "\n[Executing Specs Concurrently Across 4 Worker Threads]..."
115
- runner = Crspec::Runner.new(concurrency: 4)
116
- runner.run(Crspec.world.example_groups)
117
-
118
- puts "\n---------------- Execution Summary ----------------"
119
- puts "Total Duration : #{runner.total_duration.round(4)}s"
120
- puts "Passed Examples: #{runner.passed_examples.size}"
121
- puts "Failed Examples: #{runner.failed_examples.size}"
122
- puts "---------------------------------------------------"
123
-
124
- if runner.success?
125
- puts "\nSUCCESS: All specs executed concurrently across 4 worker threads and passed cleanly!"
126
- else
127
- puts "\nFAILURE: Some specs failed."
128
- exit 1
129
- end
@@ -1,51 +0,0 @@
1
- # See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.
2
-
3
- # Ignore git directory.
4
- /.git/
5
- /.gitignore
6
-
7
- # Ignore bundler config.
8
- /.bundle
9
-
10
- # Ignore all environment files.
11
- /.env*
12
-
13
- # Ignore all default key files.
14
- /config/master.key
15
- /config/credentials/*.key
16
-
17
- # Ignore all logfiles and tempfiles.
18
- /log/*
19
- /tmp/*
20
- !/log/.keep
21
- !/tmp/.keep
22
-
23
- # Ignore pidfiles, but keep the directory.
24
- /tmp/pids/*
25
- !/tmp/pids/.keep
26
-
27
- # Ignore storage (uploaded files in development and any SQLite databases).
28
- /storage/*
29
- !/storage/.keep
30
- /tmp/storage/*
31
- !/tmp/storage/.keep
32
-
33
- # Ignore assets.
34
- /node_modules/
35
- /app/assets/builds/*
36
- !/app/assets/builds/.keep
37
- /public/assets
38
-
39
- # Ignore CI service files.
40
- /.github
41
-
42
- # Ignore Kamal files.
43
- /config/deploy*.yml
44
- /.kamal
45
-
46
- # Ignore development files
47
- /.devcontainer
48
-
49
- # Ignore Docker-related files
50
- /.dockerignore
51
- /Dockerfile*
@@ -1,9 +0,0 @@
1
- # See https://git-scm.com/docs/gitattributes for more about git attribute files.
2
-
3
- # Mark the database schema as having been generated.
4
- db/schema.rb linguist-generated
5
-
6
- # Mark any vendored files as having been vendored.
7
- vendor/* linguist-vendored
8
- config/credentials/*.yml.enc diff=rails_credentials
9
- config/credentials.yml.enc diff=rails_credentials
@@ -1,12 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: bundler
4
- directory: "/"
5
- schedule:
6
- interval: weekly
7
- open-pull-requests-limit: 10
8
- - package-ecosystem: github-actions
9
- directory: "/"
10
- schedule:
11
- interval: weekly
12
- open-pull-requests-limit: 10
@@ -1,130 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- pull_request:
5
- push:
6
- branches: [ main ]
7
-
8
- jobs:
9
- scan_ruby:
10
- runs-on: ubuntu-latest
11
-
12
- steps:
13
- - name: Checkout code
14
- uses: actions/checkout@v6
15
-
16
- - name: Set up Ruby
17
- uses: ruby/setup-ruby@v1
18
- with:
19
- bundler-cache: true
20
-
21
- - name: Scan for common Rails security vulnerabilities using static analysis
22
- run: bin/brakeman --no-pager
23
-
24
- - name: Scan for known security vulnerabilities in gems used
25
- run: bin/bundler-audit
26
-
27
- scan_js:
28
- runs-on: ubuntu-latest
29
-
30
- steps:
31
- - name: Checkout code
32
- uses: actions/checkout@v6
33
-
34
- - name: Set up Ruby
35
- uses: ruby/setup-ruby@v1
36
- with:
37
- bundler-cache: true
38
-
39
- - name: Scan for security vulnerabilities in JavaScript dependencies
40
- run: bin/importmap audit
41
-
42
- lint:
43
- runs-on: ubuntu-latest
44
- env:
45
- RUBOCOP_CACHE_ROOT: tmp/rubocop
46
- steps:
47
- - name: Checkout code
48
- uses: actions/checkout@v6
49
-
50
- - name: Set up Ruby
51
- uses: ruby/setup-ruby@v1
52
- with:
53
- bundler-cache: true
54
-
55
- - name: Prepare RuboCop cache
56
- uses: actions/cache@v4
57
- env:
58
- DEPENDENCIES_HASH: ${{ hashFiles('.ruby-version', '**/.rubocop.yml', '**/.rubocop_todo.yml', 'Gemfile.lock') }}
59
- with:
60
- path: ${{ env.RUBOCOP_CACHE_ROOT }}
61
- key: rubocop-${{ runner.os }}-${{ env.DEPENDENCIES_HASH }}-${{ github.ref_name == github.event.repository.default_branch && github.run_id || 'default' }}
62
- restore-keys: |
63
- rubocop-${{ runner.os }}-${{ env.DEPENDENCIES_HASH }}-
64
-
65
- - name: Lint code for consistent style
66
- run: bin/rubocop -f github
67
-
68
- test:
69
- runs-on: ubuntu-latest
70
-
71
- # services:
72
- # redis:
73
- # image: valkey/valkey:8
74
- # ports:
75
- # - 6379:6379
76
- # options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
77
- steps:
78
- - name: Install packages
79
- run: sudo apt-get update && sudo apt-get install --no-install-recommends -y libvips
80
-
81
- - name: Checkout code
82
- uses: actions/checkout@v6
83
-
84
- - name: Set up Ruby
85
- uses: ruby/setup-ruby@v1
86
- with:
87
- bundler-cache: true
88
-
89
- - name: Run tests
90
- env:
91
- RAILS_ENV: test
92
- # RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
93
- # REDIS_URL: redis://localhost:6379/0
94
- run: bin/rails db:test:prepare test
95
-
96
- system-test:
97
- runs-on: ubuntu-latest
98
-
99
- # services:
100
- # redis:
101
- # image: valkey/valkey:8
102
- # ports:
103
- # - 6379:6379
104
- # options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
105
- steps:
106
- - name: Install packages
107
- run: sudo apt-get update && sudo apt-get install --no-install-recommends -y libvips
108
-
109
- - name: Checkout code
110
- uses: actions/checkout@v6
111
-
112
- - name: Set up Ruby
113
- uses: ruby/setup-ruby@v1
114
- with:
115
- bundler-cache: true
116
-
117
- - name: Run System Tests
118
- env:
119
- RAILS_ENV: test
120
- # RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
121
- # REDIS_URL: redis://localhost:6379/0
122
- run: bin/rails db:test:prepare test:system
123
-
124
- - name: Keep screenshots from failed system tests
125
- uses: actions/upload-artifact@v4
126
- if: failure()
127
- with:
128
- name: screenshots
129
- path: ${{ github.workspace }}/tmp/screenshots
130
- if-no-files-found: ignore
@@ -1,35 +0,0 @@
1
- # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
- #
3
- # Temporary files generated by your text editor or operating system
4
- # belong in git's global ignore instead:
5
- # `$XDG_CONFIG_HOME/git/ignore` or `~/.config/git/ignore`
6
-
7
- # Ignore bundler config.
8
- /.bundle
9
-
10
- # Ignore all environment files.
11
- /.env*
12
-
13
- # Ignore all logfiles and tempfiles.
14
- /log/*
15
- /tmp/*
16
- !/log/.keep
17
- !/tmp/.keep
18
-
19
- # Ignore pidfiles, but keep the directory.
20
- /tmp/pids/*
21
- !/tmp/pids/
22
- !/tmp/pids/.keep
23
-
24
- # Ignore storage (uploaded files in development and any SQLite databases).
25
- /storage/*
26
- !/storage/.keep
27
- /tmp/storage/*
28
- !/tmp/storage/
29
- !/tmp/storage/.keep
30
-
31
- /public/assets
32
-
33
- # Ignore key files for decrypting credentials and more.
34
- /config/*.key
35
-
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env sh
2
-
3
- echo "Docker set up on $KAMAL_HOSTS..."
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env sh
2
-
3
- echo "Booted app version $KAMAL_VERSION on $KAMAL_HOSTS..."
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env sh
2
-
3
- # A sample post-deploy hook
4
- #
5
- # These environment variables are available:
6
- # KAMAL_RECORDED_AT
7
- # KAMAL_PERFORMER
8
- # KAMAL_VERSION
9
- # KAMAL_HOSTS
10
- # KAMAL_ROLES (if set)
11
- # KAMAL_DESTINATION (if set)
12
- # KAMAL_RUNTIME
13
-
14
- echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds"
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env sh
2
-
3
- echo "Rebooted kamal-proxy on $KAMAL_HOSTS"
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env sh
2
-
3
- echo "Booting app version $KAMAL_VERSION on $KAMAL_HOSTS..."
@@ -1,51 +0,0 @@
1
- #!/usr/bin/env sh
2
-
3
- # A sample pre-build hook
4
- #
5
- # Checks:
6
- # 1. We have a clean checkout
7
- # 2. A remote is configured
8
- # 3. The branch has been pushed to the remote
9
- # 4. The version we are deploying matches the remote
10
- #
11
- # These environment variables are available:
12
- # KAMAL_RECORDED_AT
13
- # KAMAL_PERFORMER
14
- # KAMAL_VERSION
15
- # KAMAL_HOSTS
16
- # KAMAL_ROLES (if set)
17
- # KAMAL_DESTINATION (if set)
18
-
19
- if [ -n "$(git status --porcelain)" ]; then
20
- echo "Git checkout is not clean, aborting..." >&2
21
- git status --porcelain >&2
22
- exit 1
23
- fi
24
-
25
- first_remote=$(git remote)
26
-
27
- if [ -z "$first_remote" ]; then
28
- echo "No git remote set, aborting..." >&2
29
- exit 1
30
- fi
31
-
32
- current_branch=$(git branch --show-current)
33
-
34
- if [ -z "$current_branch" ]; then
35
- echo "Not on a git branch, aborting..." >&2
36
- exit 1
37
- fi
38
-
39
- remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1)
40
-
41
- if [ -z "$remote_head" ]; then
42
- echo "Branch not pushed to remote, aborting..." >&2
43
- exit 1
44
- fi
45
-
46
- if [ "$KAMAL_VERSION" != "$remote_head" ]; then
47
- echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2
48
- exit 1
49
- fi
50
-
51
- exit 0
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # A sample pre-connect check
4
- #
5
- # Warms DNS before connecting to hosts in parallel
6
- #
7
- # These environment variables are available:
8
- # KAMAL_RECORDED_AT
9
- # KAMAL_PERFORMER
10
- # KAMAL_VERSION
11
- # KAMAL_HOSTS
12
- # KAMAL_ROLES (if set)
13
- # KAMAL_DESTINATION (if set)
14
- # KAMAL_RUNTIME
15
-
16
- hosts = ENV["KAMAL_HOSTS"].split(",")
17
- results = nil
18
- max = 3
19
-
20
- elapsed = Benchmark.realtime do
21
- results = hosts.map do |host|
22
- Thread.new do
23
- tries = 1
24
-
25
- begin
26
- Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
27
- rescue SocketError
28
- if tries < max
29
- puts "Retrying DNS warmup: #{host}"
30
- tries += 1
31
- sleep rand
32
- retry
33
- else
34
- puts "DNS warmup failed: #{host}"
35
- host
36
- end
37
- end
38
-
39
- tries
40
- end
41
- end.map(&:value)
42
- end
43
-
44
- retries = results.sum - hosts.size
45
- nopes = results.count { |r| r == max }
46
-
47
- puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ]
@@ -1,122 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # A sample pre-deploy hook
4
- #
5
- # Checks the Github status of the build, waiting for a pending build to complete for up to 720 seconds.
6
- #
7
- # Fails unless the combined status is "success"
8
- #
9
- # These environment variables are available:
10
- # KAMAL_RECORDED_AT
11
- # KAMAL_PERFORMER
12
- # KAMAL_VERSION
13
- # KAMAL_HOSTS
14
- # KAMAL_COMMAND
15
- # KAMAL_SUBCOMMAND
16
- # KAMAL_ROLES (if set)
17
- # KAMAL_DESTINATION (if set)
18
-
19
- # Only check the build status for production deployments
20
- if ENV["KAMAL_COMMAND"] == "rollback" || ENV["KAMAL_DESTINATION"] != "production"
21
- exit 0
22
- end
23
-
24
- require "bundler/inline"
25
-
26
- # true = install gems so this is fast on repeat invocations
27
- gemfile(true, quiet: true) do
28
- source "https://rubygems.org"
29
-
30
- gem "octokit"
31
- gem "faraday-retry"
32
- end
33
-
34
- MAX_ATTEMPTS = 72
35
- ATTEMPTS_GAP = 10
36
-
37
- def exit_with_error(message)
38
- $stderr.puts message
39
- exit 1
40
- end
41
-
42
- class GithubStatusChecks
43
- attr_reader :remote_url, :git_sha, :github_client, :combined_status
44
-
45
- def initialize
46
- @remote_url = github_repo_from_remote_url
47
- @git_sha = `git rev-parse HEAD`.strip
48
- @github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
49
- refresh!
50
- end
51
-
52
- def refresh!
53
- @combined_status = github_client.combined_status(remote_url, git_sha)
54
- end
55
-
56
- def state
57
- combined_status[:state]
58
- end
59
-
60
- def first_status_url
61
- first_status = combined_status[:statuses].find { |status| status[:state] == state }
62
- first_status && first_status[:target_url]
63
- end
64
-
65
- def complete_count
66
- combined_status[:statuses].count { |status| status[:state] != "pending"}
67
- end
68
-
69
- def total_count
70
- combined_status[:statuses].count
71
- end
72
-
73
- def current_status
74
- if total_count > 0
75
- "Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..."
76
- else
77
- "Build not started..."
78
- end
79
- end
80
-
81
- private
82
- def github_repo_from_remote_url
83
- url = `git config --get remote.origin.url`.strip.delete_suffix(".git")
84
- if url.start_with?("https://github.com/")
85
- url.delete_prefix("https://github.com/")
86
- elsif url.start_with?("git@github.com:")
87
- url.delete_prefix("git@github.com:")
88
- else
89
- url
90
- end
91
- end
92
- end
93
-
94
-
95
- $stdout.sync = true
96
-
97
- begin
98
- puts "Checking build status..."
99
-
100
- attempts = 0
101
- checks = GithubStatusChecks.new
102
-
103
- loop do
104
- case checks.state
105
- when "success"
106
- puts "Checks passed, see #{checks.first_status_url}"
107
- exit 0
108
- when "failure"
109
- exit_with_error "Checks failed, see #{checks.first_status_url}"
110
- when "pending"
111
- attempts += 1
112
- end
113
-
114
- exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS
115
-
116
- puts checks.current_status
117
- sleep(ATTEMPTS_GAP)
118
- checks.refresh!
119
- end
120
- rescue Octokit::NotFound
121
- exit_with_error "Build status could not be found"
122
- end
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env sh
2
-
3
- echo "Rebooting kamal-proxy on $KAMAL_HOSTS..."
@@ -1,20 +0,0 @@
1
- # Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,
2
- # and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
3
- # password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git.
4
-
5
- # Example of extracting secrets from 1password (or another compatible pw manager)
6
- # SECRETS=$(kamal secrets fetch --adapter 1password --account your-account --from Vault/Item KAMAL_REGISTRY_PASSWORD RAILS_MASTER_KEY)
7
- # KAMAL_REGISTRY_PASSWORD=$(kamal secrets extract KAMAL_REGISTRY_PASSWORD ${SECRETS})
8
- # RAILS_MASTER_KEY=$(kamal secrets extract RAILS_MASTER_KEY ${SECRETS})
9
-
10
- # Example of extracting secrets from Rails credentials
11
- # KAMAL_REGISTRY_PASSWORD=$(rails credentials:fetch kamal.registry_password)
12
-
13
- # Use a GITHUB_TOKEN if private repositories are needed for the image
14
- # GITHUB_TOKEN=$(gh config get -h github.com oauth_token)
15
-
16
- # Grab the registry password from ENV
17
- # KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
18
-
19
- # Improve security by using a password manager. Never check config/master.key into git!
20
- RAILS_MASTER_KEY=$(cat config/master.key)
@@ -1,8 +0,0 @@
1
- # Omakase Ruby styling for Rails
2
- inherit_gem: { rubocop-rails-omakase: rubocop.yml }
3
-
4
- # Overwrite or add rules to create your own house style
5
- #
6
- # # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
7
- # Layout/SpaceInsideArrayLiteralBrackets:
8
- # Enabled: false