specwrk 0.1.4 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40f4d401d702b91aeb83be0c46ce7ca36cef7c672adf2d5d3b1cdba036121067
4
- data.tar.gz: cb7e0992a6003a88a0468f9d08ba90a2922866a36cb53a844740c9409fc9254e
3
+ metadata.gz: 620355ee669758b42abdd60b638044fbe7bbc4880d51356ea20e9785ab1bb4e3
4
+ data.tar.gz: 4444c229b60e2b83b5adfc620290965c1a866d5de0cdcfab8a63fab4a7948312
5
5
  SHA512:
6
- metadata.gz: bfa583f503773db843aba2e962878a00f7cc8c38cfe2cd2c56ab5165394c4a586345347afcb1efef626e920f05fe95afe949f89e1c97a5000d3477ebb0e2bea5
7
- data.tar.gz: 53bb263d94bd76886d1800f80a3a9fd8270938c7e794ad983f9c843020e0da9abaeec5c2bb664ba3642b02f2fa2b2c8f8cd537216e5af96b38d302d8cd90538e
6
+ metadata.gz: ec37f9d67476e6e0ce8ac12d970dc153ca4cdcec1f931b4e35973d71f05459599e8e38b750d8a5bfd81bc218866bc55f1e9dacc561340d9d67fa75b437cd4efa
7
+ data.tar.gz: 5267ffee5481ca36ce19559e84bc1c276de5351abe755950f22d2b8a2047ba931376d6c07adc69fd678375487d120964c04c090bdb5f121c32cde433d61bfe59
data/README.md CHANGED
@@ -1,4 +1,165 @@
1
1
  # Specwrk
2
+ Run your [RSpec](https://github.com/rspec/rspec) examples across many processors and many nodes for a single build. Or just many processes on a single node. Speeds up your *slow* (minutes/hours not seconds) test suite by running multiple examples in parallel.
3
+
4
+ One CLI command to:
5
+
6
+ 1. Start a queue server for your current build
7
+ 2. Seed the queue server with all possible examples in the current project
8
+ 3. Execute
9
+
10
+ ## Install
11
+ Start by adding specwrk to your project or installing it.
12
+ ```sh
13
+ $ bundle add specwrk -g development,test
14
+ ```
15
+ ```sh
16
+ $ gem install specwrk
17
+ ```
18
+
19
+ ## CLI
20
+
21
+ ```sh
22
+ $ specwrk --help
23
+
24
+ Commands:
25
+ specwrk seed [DIR] # Seed the server with a list of specs for the run
26
+ specwrk serve # Start a queue server
27
+ specwrk start [DIR] # Start a server and workers, monitor until complete
28
+ specwrk version # Print version
29
+ specwrk work # Start one or more worker processes
30
+ ```
31
+
32
+ ### `specwrk start -c 8 spec/`
33
+ Indended for quick-adhoc runs in development. This command starts a queue server, seeds it with examples from the `spec/` directory, and starts `8` worker processes. It will report the ultimate success or failure.
34
+
35
+ ```sh
36
+ $ start --help
37
+ Command:
38
+ specwrk start
39
+
40
+ Usage:
41
+ specwrk start [DIR]
42
+
43
+ Description:
44
+ Start a server and workers, monitor until complete
45
+
46
+ Arguments:
47
+ DIR # Relative spec directory to run against
48
+
49
+ Options:
50
+ --uri=VALUE # HTTP URI of the server to pull jobs from. Overrides SPECWRK_SRV_PORT. Default 5138., default: "https://localhost:5138"
51
+ --key=VALUE, -k VALUE # Authentication key clients must use for access. Overrides SPECWRK_SRV_KEY. Default ''., default: ""
52
+ --run=VALUE, -r VALUE # The run identifier for this job execution. Overrides SPECWRK_RUN. Default main., default: "main"
53
+ --timeout=VALUE, -t VALUE # The amount of time to wait for the server to respond. Overrides SPECWRK_TIMEOUT. Default 5., default: "5"
54
+ --id=VALUE # The identifier for this worker. Default specwrk-worker(-COUNT_INDEX)., default: "specwrk-worker"
55
+ --count=VALUE, -c VALUE # The number of worker processes you want to start. Default 1., default: 1
56
+ --output=VALUE, -o VALUE # Directory where worker output is stored. Overrides SPECWRK_OUT. Default '.specwrk/'., default: ".specwrk/"
57
+ --port=VALUE, -p VALUE # Server port. Overrides SPECWRK_SRV_PORT. Default 5138., default: "5138"
58
+ --bind=VALUE, -b VALUE # Server bind address. Overrides SPECWRK_SRV_BIND. Default 127.0.0.1., default: "127.0.0.1"
59
+ --group-by=VALUE # How examples will be grouped for workers; fallback to file if no timings are found. Overrides SPECWERK_SRV_GROUP_BY. Default timings.: (file/timings), default: "timings"
60
+ --[no-]single-run # Act on shutdown requests from clients. Default: false., default: false
61
+ --[no-]verbose # Run in verbose mode. Default false., default: false
62
+ --help, -h # Print this help
63
+ ```
64
+
65
+ ### `specwrk serve`
66
+ Only start the server process. Intended for use in CI pipelines.
67
+
68
+ ```sh
69
+ $ specwrk serve --help
70
+ Command:
71
+ specwrk serve
72
+
73
+ Usage:
74
+ specwrk serve
75
+
76
+ Description:
77
+ Start a queue server
78
+
79
+ Options:
80
+ --port=VALUE, -p VALUE # Server port. Overrides SPECWRK_SRV_PORT. Default 5138., default: "5138"
81
+ --bind=VALUE, -b VALUE # Server bind address. Overrides SPECWRK_SRV_BIND. Default 127.0.0.1., default: "127.0.0.1"
82
+ --key=VALUE, -k VALUE # Authentication key clients must use for access. Overrides SPECWRK_SRV_KEY. Default ''., default: ""
83
+ --output=VALUE, -o VALUE # Directory where worker output is stored. Overrides SPECWRK_OUT. Default '.specwrk/'., default: ".specwrk/"
84
+ --group-by=VALUE # How examples will be grouped for workers; fallback to file if no timings are found. Overrides SPECWERK_SRV_GROUP_BY. Default timings.: (file/timings), default: "timings"
85
+ --[no-]single-run # Act on shutdown requests from clients. Default: false., default: false
86
+ --[no-]verbose # Run in verbose mode. Default false., default: false
87
+ --help, -h # Print this help
88
+ ```
89
+
90
+ ### `specwrk seed spec/`
91
+ Seed the configured server with examples from the `spec/` directory. Intended for use in CI pipelines.
92
+
93
+ ```sh
94
+ specwrk seed --help
95
+ Command:
96
+ specwrk seed
97
+
98
+ Usage:
99
+ specwrk seed [DIR]
100
+
101
+ Description:
102
+ Seed the server with a list of specs for the run
103
+
104
+ Arguments:
105
+ DIR # Relative spec directory to run against
106
+
107
+ Options:
108
+ --uri=VALUE # HTTP URI of the server to pull jobs from. Overrides SPECWRK_SRV_PORT. Default 5138., default: "https://localhost:5138"
109
+ --key=VALUE, -k VALUE # Authentication key clients must use for access. Overrides SPECWRK_SRV_KEY. Default ''., default: ""
110
+ --run=VALUE, -r VALUE # The run identifier for this job execution. Overrides SPECWRK_RUN. Default main., default: "main"
111
+ --timeout=VALUE, -t VALUE # The amount of time to wait for the server to respond. Overrides SPECWRK_TIMEOUT. Default 5., default: "5"
112
+ --help, -h # Print this help
113
+ ```
114
+
115
+ ### `specwrk work -c 8`
116
+ Starts `8` worker processes which will pull examples off the seeded server. Intended for use in CI pipelines.
117
+
118
+ ```sh
119
+ $ specwrk work --help
120
+ Command:
121
+ specwrk work
122
+
123
+ Usage:
124
+ specwrk work
125
+
126
+ Description:
127
+ Start one or more worker processes
128
+
129
+ Options:
130
+ --id=VALUE # The identifier for this worker. Default specwrk-worker(-COUNT_INDEX)., default: "specwrk-worker"
131
+ --count=VALUE, -c VALUE # The number of worker processes you want to start. Default 1., default: 1
132
+ --output=VALUE, -o VALUE # Directory where worker output is stored. Overrides SPECWRK_OUT. Default '.specwrk/'., default: ".specwrk/"
133
+ --uri=VALUE # HTTP URI of the server to pull jobs from. Overrides SPECWRK_SRV_PORT. Default 5138., default: "https://localhost:5138"
134
+ --key=VALUE, -k VALUE # Authentication key clients must use for access. Overrides SPECWRK_SRV_KEY. Default ''., default: ""
135
+ --run=VALUE, -r VALUE # The run identifier for this job execution. Overrides SPECWRK_RUN. Default main., default: "main"
136
+ --timeout=VALUE, -t VALUE # The amount of time to wait for the server to respond. Overrides SPECWRK_TIMEOUT. Default 5., default: "5"
137
+ --help, -h # Print this help
138
+ ```
139
+
140
+ ## Configuring your test environment
141
+ If you test suite tracks state, starts servers, etc. and you plan on running many processes on the same node, you'll need to make
142
+ adjustments to avoid conflicting port usage or database/state mutations.
143
+
144
+ `specwrk` workers will have `TEST_ENV_NUMBER={i}` set to help you configure approriately.
145
+
146
+ ### Rails
147
+ Rails has had easy multi-process test setup for a while now by creating unique test databases per process. For my rails v7.2 app which uses PostgreSQL and Capyabara, I made these changes to my `spec/rails_helper.rb`:
148
+
149
+ ```diff
150
+ ++ if ENV["TEST_ENV_NUMBER"]
151
+ ++ ActiveRecord::TestDatabases.create_and_load_schema(
152
+ ++ ENV["TEST_ENV_NUMBER"].to_i, env_name: ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
153
+ ++ )
154
+ ++ end
155
+ -- Capybara.server_port = 5550
156
+ ++ Capybara.server_port = 5550 + ENV.fetch("TEST_ENV_NUMBER", "1").to_i
157
+ ++ Capybara.always_include_port = true
158
+ ```
159
+
160
+ ## CI
161
+ 1 server N nodes with N processes => 🏎️
162
+
2
163
  TODO!
3
164
 
4
165
  ## Contributing
@@ -0,0 +1,20 @@
1
+ FROM ruby:3.4-alpine
2
+
3
+ WORKDIR /app
4
+
5
+ RUN mkdir .specwrk/
6
+
7
+ ARG SPECWRK_SRV_PORT=5138
8
+ ARG SPECWRK_VERSION=latest
9
+ ARG GEMFILE=specwrk-$SPECWRK_VERSION.gem
10
+
11
+ COPY $GEMFILE ./
12
+ RUN gem install ./$GEMFILE --no-document
13
+ RUN rm ./$GEMFILE
14
+
15
+ COPY docker/entrypoint.server.sh /usr/local/bin/entrypoint
16
+ RUN chmod +x /usr/local/bin/entrypoint
17
+
18
+ EXPOSE ${SPECWRK_SRV_PORT}
19
+
20
+ ENTRYPOINT ["entrypoint"]
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ exec specwrk serve --port ${PORT:-$SPECWRK_SRV_PORT} --bind 0.0.0.0 --no-single-run --verbose
data/lib/specwrk/cli.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "pathname"
4
+ require "fileutils"
4
5
 
5
6
  require "dry/cli"
6
7
 
@@ -15,7 +16,7 @@ module Specwrk
15
16
  extend Hookable
16
17
 
17
18
  on_included do |base|
18
- base.unique_option :uri, type: :string, default: ENV.fetch("SPECWRK_SRV_URI", "https://localhost:#{ENV.fetch("SPECWRK_SRV_PORT", "5138")}"), desc: "HTTP URI of the server to pull jobs from. Overrides SPECWRK_SRV_PORT. Default 5138."
19
+ base.unique_option :uri, type: :string, default: ENV.fetch("SPECWRK_SRV_URI", "http://localhost:#{ENV.fetch("SPECWRK_SRV_PORT", "5138")}"), desc: "HTTP URI of the server to pull jobs from. Overrides SPECWRK_SRV_PORT. Default 5138."
19
20
  base.unique_option :key, type: :string, default: ENV.fetch("SPECWRK_SRV_KEY", ""), aliases: ["-k"], desc: "Authentication key clients must use for access. Overrides SPECWRK_SRV_KEY. Default ''."
20
21
  base.unique_option :run, type: :string, default: ENV.fetch("SPECWRK_RUN", "main"), aliases: ["-r"], desc: "The run identifier for this job execution. Overrides SPECWRK_RUN. Default main."
21
22
  base.unique_option :timeout, type: :integer, default: ENV.fetch("SPECWRK_TIMEOUT", "5"), aliases: ["-t"], desc: "The amount of time to wait for the server to respond. Overrides SPECWRK_TIMEOUT. Default 5."
@@ -42,6 +43,7 @@ module Specwrk
42
43
  ENV["SPECWRK_ID"] = id
43
44
  ENV["SPECWRK_COUNT"] = count.to_s
44
45
  ENV["SPECWRK_OUT"] = Pathname.new(output).expand_path(Dir.pwd).to_s
46
+ FileUtils.mkdir_p(ENV["SPECWRK_OUT"])
45
47
  end
46
48
 
47
49
  def start_workers
@@ -52,7 +54,8 @@ module Specwrk
52
54
 
53
55
  require "specwrk/worker"
54
56
 
55
- Specwrk::Worker.run!
57
+ status = Specwrk::Worker.run!
58
+ exit(status)
56
59
  end
57
60
  end
58
61
  end
@@ -75,10 +78,14 @@ module Specwrk
75
78
  base.unique_option :verbose, type: :boolean, default: false, desc: "Run in verbose mode. Default false."
76
79
  end
77
80
 
78
- on_setup do |output:, port:, key:, single_run:, group_by:, verbose:, **|
79
- ENV["SPECWRK_SRV_LOG"] = Pathname.new(File.join(output, "server.log")).expand_path(Dir.pwd).to_s if output && !verbose
80
- ENV["SPECWRK_SRV_OUTPUT"] = Pathname.new(File.join(output, "report.json")).expand_path(Dir.pwd).to_s if output
81
+ on_setup do |port:, bind:, output:, key:, single_run:, group_by:, verbose:, **|
82
+ ENV["SPECWRK_OUT"] = Pathname.new(output).expand_path(Dir.pwd).to_s
83
+ FileUtils.mkdir_p(ENV["SPECWRK_OUT"])
84
+
85
+ ENV["SPECWRK_SRV_LOG"] ||= Pathname.new(File.join(ENV["SPECWRK_OUT"], "server.log")).to_s if output && !verbose
86
+ ENV["SPECWRK_SRV_OUTPUT"] ||= Pathname.new(File.join(ENV["SPECWRK_OUT"], "report.json")).expand_path(Dir.pwd).to_s if output
81
87
  ENV["SPECWRK_SRV_PORT"] = port
88
+ ENV["SPECWRK_SRV_BIND"] = bind
82
89
  ENV["SPECWRK_SRV_KEY"] = key
83
90
  ENV["SPECWRK_SRV_SINGLE_RUN"] = "1" if single_run
84
91
  ENV["SPECWRK_SRV_GROUP_BY"] = group_by
@@ -127,13 +134,21 @@ module Specwrk
127
134
  self.class.setup(**args)
128
135
 
129
136
  start_workers
130
- Process.waitall
137
+ wait_for_workers_exit
131
138
 
132
139
  require "specwrk/cli_reporter"
133
- status = Specwrk::CLIReporter.new.report
140
+ Specwrk::CLIReporter.new.report
134
141
 
135
142
  exit(status)
136
143
  end
144
+
145
+ def wait_for_workers_exit
146
+ @exited_pids = Specwrk.wait_for_pids_exit(@worker_pids)
147
+ end
148
+
149
+ def status
150
+ @exited_pids.value?(1) ? 1 : 0
151
+ end
137
152
  end
138
153
 
139
154
  class Serve < Dry::CLI::Command
@@ -188,44 +203,24 @@ module Specwrk
188
203
  status "Samples seeded ✓"
189
204
  end
190
205
 
191
- wait_for_pids_exit([seed_pid])
206
+ Specwrk.wait_for_pids_exit([seed_pid])
192
207
 
193
208
  return if Specwrk.force_quit
194
209
  status "Starting #{worker_count} workers..."
195
210
  start_workers
196
211
 
197
212
  status "#{worker_count} workers started ✓\n"
198
- wait_for_pids_exit(@worker_pids)
213
+ Specwrk.wait_for_pids_exit(@worker_pids)
199
214
 
200
215
  return if Specwrk.force_quit
201
216
 
202
217
  require "specwrk/cli_reporter"
203
218
  status = Specwrk::CLIReporter.new.report
204
219
 
205
- wait_for_pids_exit([web_pid, seed_pid] + @worker_pids)
220
+ Specwrk.wait_for_pids_exit([web_pid, seed_pid] + @worker_pids)
206
221
  exit(status)
207
222
  end
208
223
 
209
- def wait_for_pids_exit(pids)
210
- exited_pids = {}
211
-
212
- loop do
213
- pids.each do |pid|
214
- next if exited_pids.key? pid
215
-
216
- _, status = Process.waitpid2(pid, Process::WNOHANG)
217
- exited_pids[pid] = status.exitstatus if status&.exitstatus
218
- rescue Errno::ECHILD
219
- exited_pids[pid] = 0
220
- end
221
-
222
- break if exited_pids.keys.length == pids.length
223
- sleep 0.1
224
- end
225
-
226
- exited_pids
227
- end
228
-
229
224
  def status(msg)
230
225
  print "\e[2K\r#{msg}"
231
226
  $stdout.flush
@@ -4,6 +4,12 @@ require "uri"
4
4
  require "net/http"
5
5
  require "json"
6
6
 
7
+ require "specwrk"
8
+
9
+ # Some rspec setups might use webmock, which intercepts specwrk server calls
10
+ # Let's capture the OG HTTP before that happens
11
+ Specwrk.net_http = Net::HTTP
12
+
7
13
  module Specwrk
8
14
  class Client
9
15
  def self.connect?
@@ -18,7 +24,8 @@ module Specwrk
18
24
 
19
25
  def self.build_http
20
26
  uri = URI(ENV.fetch("SPECWRK_SRV_URI", "http://localhost:5138"))
21
- Net::HTTP.new(uri.host, uri.port).tap do |http|
27
+ Specwrk.net_http.new(uri.host, uri.port).tap do |http|
28
+ http.use_ssl = uri.scheme == "https"
22
29
  http.open_timeout = ENV.fetch("SPECWRK_TIMEOUT", "5").to_i
23
30
  http.read_timeout = ENV.fetch("SPECWRK_TIMEOUT", "5").to_i
24
31
  http.keep_alive_timeout = 300
@@ -105,28 +112,28 @@ module Specwrk
105
112
  private
106
113
 
107
114
  def get(path, headers: default_headers, body: nil)
108
- request = Net::HTTP::Get.new(path, headers)
115
+ request = Specwrk.net_http::Get.new(path, headers)
109
116
  request.body = body if body
110
117
 
111
118
  make_request(request)
112
119
  end
113
120
 
114
121
  def post(path, headers: default_headers, body: nil)
115
- request = Net::HTTP::Post.new(path, headers)
122
+ request = Specwrk.net_http::Post.new(path, headers)
116
123
  request.body = body if body
117
124
 
118
125
  make_request(request)
119
126
  end
120
127
 
121
128
  def put(path, headers: default_headers, body: nil)
122
- request = Net::HTTP::Put.new(path, headers)
129
+ request = Specwrk.net_http::Put.new(path, headers)
123
130
  request.body = body if body
124
131
 
125
132
  make_request(request)
126
133
  end
127
134
 
128
135
  def delete(path, headers: default_headers, body: nil)
129
- request = Net::HTTP::Delete.new(path, headers)
136
+ request = Specwrk.net_http::Delete.new(path, headers)
130
137
  request.body = body if body
131
138
 
132
139
  make_request(request)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Specwrk
4
- VERSION = "0.1.4"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -27,7 +27,7 @@ module Specwrk
27
27
 
28
28
  server_opts = {
29
29
  Port: ENV.fetch("SPECWRK_SRV_PORT", "5138").to_i,
30
- Host: ENV.fetch("SPECWRK_SRV_BIND", "127.0.0.1"),
30
+ BindAddress: ENV.fetch("SPECWRK_SRV_BIND", "127.0.0.1"),
31
31
  Logger: WEBrick::Log.new($stdout, WEBrick::Log::FATAL),
32
32
  AccessLog: [],
33
33
  KeepAliveTimeout: 300
@@ -5,23 +5,28 @@ module Specwrk
5
5
  class CompletionFormatter
6
6
  RSpec::Core::Formatters.register self, :stop
7
7
 
8
- attr_reader :examples
8
+ attr_reader :examples, :failure
9
9
 
10
10
  def initialize
11
11
  @examples = []
12
+ @failure = false
12
13
  end
13
14
 
14
15
  def stop(group_notification)
15
16
  group_notification.notifications.map do |notification|
17
+ unless failure
18
+ @failure = notification.example.execution_result.status == :failed
19
+ end
20
+
16
21
  examples << {
17
22
  id: notification.example.id,
18
23
  full_description: notification.example.full_description,
19
- status: notification.example.metadata[:execution_result].status,
24
+ status: notification.example.execution_result.status,
20
25
  file_path: notification.example.metadata[:file_path],
21
26
  line_number: notification.example.metadata[:line_number],
22
- started_at: notification.example.metadata[:execution_result].started_at.iso8601(6),
23
- finished_at: notification.example.metadata[:execution_result].finished_at.iso8601(6),
24
- run_time: notification.example.metadata[:execution_result].run_time
27
+ started_at: notification.example.execution_result.started_at.iso8601(6),
28
+ finished_at: notification.example.execution_result.finished_at.iso8601(6),
29
+ run_time: notification.example.execution_result.run_time
25
30
  }
26
31
  end
27
32
  end
@@ -11,6 +11,10 @@ require "specwrk/worker/null_formatter"
11
11
  module Specwrk
12
12
  class Worker
13
13
  class Executor
14
+ def failure
15
+ completion_formatter.failure
16
+ end
17
+
14
18
  def examples
15
19
  completion_formatter.examples
16
20
  end
@@ -29,19 +29,27 @@ module Specwrk
29
29
  break if Specwrk.force_quit
30
30
 
31
31
  execute
32
- rescue CompletedAllExamplesError, NoMoreExamplesError
33
- # TODO: Sleep on NoMoreExamplesError to allow for retries
32
+ rescue CompletedAllExamplesError
34
33
  break
34
+ rescue NoMoreExamplesError
35
+ # Wait for the other processes (workers) on the same host to finish
36
+ # This will cause workers to 'hang' until all work has been completed
37
+ # TODO: break here if all the other worker processes on this host are done executing examples
38
+ sleep 0.5
35
39
  end
36
40
 
37
41
  executor.final_output.tap(&:rewind).each_line { |line| $stdout.write line }
38
42
 
39
43
  @heartbeat_thread.kill
40
44
  client.close
45
+
46
+ status
41
47
  rescue Errno::ECONNREFUSED
42
48
  warn "\nServer at #{ENV.fetch("SPECWRK_SRV_URI", "http://localhost:5138")} is refusing connections, exiting..."
49
+ 1
43
50
  rescue Errno::ECONNRESET
44
51
  warn "\nServer at #{ENV.fetch("SPECWRK_SRV_URI", "http://localhost:5138")} stopped responding to connections, exiting..."
52
+ 1
45
53
  end
46
54
 
47
55
  def execute
@@ -79,6 +87,13 @@ module Specwrk
79
87
 
80
88
  attr_reader :running, :client, :executor
81
89
 
90
+ def status
91
+ return 1 if executor.failure
92
+ return 1 if Specwrk.force_quit
93
+
94
+ 0
95
+ end
96
+
82
97
  def warn(msg)
83
98
  super("#{ENV.fetch("SPECWRK_ID", "specwrk-worker")}: #{msg}")
84
99
  end
data/lib/specwrk.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "specwrk/version"
3
+ require "specwrk/version"
4
4
 
5
5
  module Specwrk
6
6
  Error = Class.new(StandardError)
@@ -15,7 +15,27 @@ module Specwrk
15
15
  @starting_pid = Process.pid
16
16
 
17
17
  class << self
18
- attr_accessor :force_quit
18
+ attr_accessor :force_quit, :net_http
19
19
  attr_reader :starting_pid
20
+
21
+ def wait_for_pids_exit(pids)
22
+ exited_pids = {}
23
+
24
+ loop do
25
+ pids.each do |pid|
26
+ next if exited_pids.key? pid
27
+
28
+ _, status = Process.waitpid2(pid, Process::WNOHANG)
29
+ exited_pids[pid] = status.exitstatus if status&.exitstatus
30
+ rescue Errno::ECHILD
31
+ exited_pids[pid] = 1
32
+ end
33
+
34
+ break if exited_pids.keys.length == pids.length
35
+ sleep 0.1
36
+ end
37
+
38
+ exited_pids
39
+ end
20
40
  end
21
41
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: specwrk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Westendorf
@@ -121,6 +121,20 @@ dependencies:
121
121
  - - ">="
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
+ - !ruby/object:Gem::Dependency
125
+ name: gem-release
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
124
138
  email:
125
139
  - daniel@prowestech.com
126
140
  executables:
@@ -134,6 +148,8 @@ files:
134
148
  - LICENSE.txt
135
149
  - README.md
136
150
  - Rakefile
151
+ - docker/Dockerfile.server
152
+ - docker/entrypoint.server.sh
137
153
  - exe/specwrk
138
154
  - lib/specwrk.rb
139
155
  - lib/specwrk/cli.rb
@@ -155,7 +171,7 @@ files:
155
171
  - lib/specwrk/worker/progress_formatter.rb
156
172
  homepage: https://github.com/danielwestendorf/specwrk
157
173
  licenses:
158
- - LGPLv3
174
+ - GPL-3.0-or-later
159
175
  metadata:
160
176
  homepage_uri: https://github.com/danielwestendorf/specwrk
161
177
  source_code_uri: https://github.com/danielwestendorf/specwrk