gush 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +71 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +12 -5
- data/Gemfile +4 -0
- data/README.md +37 -8
- data/bin/gush +2 -2
- data/gush.gemspec +8 -9
- data/lib/gush/cli/overview.rb +13 -13
- data/lib/gush/cli.rb +51 -20
- data/lib/gush/client.rb +39 -57
- data/lib/gush/configuration.rb +14 -10
- data/lib/gush/graph.rb +43 -32
- data/lib/gush/worker.rb +18 -2
- data/spec/features/integration_spec.rb +5 -7
- data/spec/gush/client_spec.rb +8 -2
- data/spec/gush/configuration_spec.rb +6 -0
- data/spec/gush/graph_spec.rb +37 -20
- data/spec/gush/worker_spec.rb +20 -0
- data/spec/spec_helper.rb +18 -9
- metadata +36 -39
- data/.travis.yml +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc70498c39ad506749bed1f55c139d29691e540b849dd39e2ba132b54b511d66
|
4
|
+
data.tar.gz: 700d093574e0ff4772c7d36bfeb7792cda44550dd162a48afe17bec5551250cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac4c1647f57a87600466445a8d24660e3d95016f17adf9e2fe8f99260ba82a2b3e22a339b9456f653834c89c6e4b9ed6bcb50ebc337b804e07355f9a513ce8ca
|
7
|
+
data.tar.gz: 1ae01511acfc2e23bb0a671328a7b3e9b650b8589b9620461c2b9667ff9d80a47f03b8a156f249746b4f69e613863db0833be8d6221acdabd211d7eba2daee15
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
pull_request:
|
12
|
+
paths-ignore:
|
13
|
+
- 'README.md'
|
14
|
+
push:
|
15
|
+
paths-ignore:
|
16
|
+
- 'README.md'
|
17
|
+
|
18
|
+
jobs:
|
19
|
+
test:
|
20
|
+
services:
|
21
|
+
redis:
|
22
|
+
image: redis:alpine
|
23
|
+
ports: ["6379:6379"]
|
24
|
+
options: --entrypoint redis-server
|
25
|
+
|
26
|
+
runs-on: ubuntu-latest
|
27
|
+
strategy:
|
28
|
+
matrix:
|
29
|
+
rails_version: ['4.2.7', '5.1.0', '5.2.0', '6.0.0', '6.1.0', '7.0']
|
30
|
+
ruby-version: ['2.6', '2.7', '3.0', '3.1']
|
31
|
+
exclude:
|
32
|
+
- ruby-version: '3.0'
|
33
|
+
rails_version: '4.2.7'
|
34
|
+
- ruby-version: '3.1'
|
35
|
+
rails_version: '4.2.7'
|
36
|
+
- ruby-version: '3.0'
|
37
|
+
rails_version: '5.0'
|
38
|
+
- ruby-version: '3.1'
|
39
|
+
rails_version: '5.0'
|
40
|
+
- ruby-version: '3.0'
|
41
|
+
rails_version: '5.1'
|
42
|
+
- ruby-version: '3.1'
|
43
|
+
rails_version: '5.1'
|
44
|
+
- ruby-version: '3.0'
|
45
|
+
rails_version: '5.2'
|
46
|
+
- ruby-version: '3.1'
|
47
|
+
rails_version: '5.2'
|
48
|
+
- ruby-version: '3.0'
|
49
|
+
rails_version: '6.0'
|
50
|
+
- ruby-version: '3.1'
|
51
|
+
rails_version: '6.0'
|
52
|
+
- ruby-version: '3.1'
|
53
|
+
rails_version: '6.1'
|
54
|
+
- ruby-version: '2.6'
|
55
|
+
rails_version: '7.0'
|
56
|
+
steps:
|
57
|
+
- uses: actions/checkout@v2
|
58
|
+
- name: Set up Ruby
|
59
|
+
uses: ruby/setup-ruby@v1
|
60
|
+
with:
|
61
|
+
ruby-version: ${{ matrix.ruby-version }}
|
62
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
63
|
+
env:
|
64
|
+
RAILS_VERSION: "${{ matrix.rails_version }}"
|
65
|
+
- name: Install Graphviz
|
66
|
+
run: sudo apt-get install graphviz
|
67
|
+
- name: Run tests
|
68
|
+
run: bundle exec rspec
|
69
|
+
env:
|
70
|
+
REDIS_URL: redis://localhost:6379/1
|
71
|
+
RAILS_VERSION: "${{ matrix.rails_version }}"
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## 2.1.0
|
9
|
+
|
10
|
+
### Added
|
11
|
+
|
12
|
+
- Allow RedisMutex’s locking duration and polling interval to be customizable, thanks to @thukim! [See pull request](https://github.com/chaps-io/gush/pull/74)
|
13
|
+
- Support for Rails 7.0 and Ruby 3.0-3.1, thanks to @joshRpowell and @kzkn!
|
14
|
+
|
8
15
|
## 2.0.1
|
9
16
|
|
10
17
|
### Fixed
|
@@ -13,31 +20,31 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
13
20
|
|
14
21
|
## 2.0.0
|
15
22
|
|
16
|
-
|
23
|
+
### Changed
|
17
24
|
|
18
25
|
- *[BREAKING]* Store gush jobs on redis hash instead of plain keys - this improves performance when retrieving keys (Thanks to @Saicheg! [See pull request](https://github.com/chaps-io/gush/pull/56))
|
19
26
|
|
20
27
|
|
21
|
-
|
28
|
+
### Added
|
22
29
|
|
23
30
|
- Allow setting queue for each job via `:queue` option in `run` method (Thanks to @devilankur18! [See pull request](https://github.com/chaps-io/gush/pull/58))
|
24
31
|
|
25
32
|
|
26
33
|
## 1.1.1 - 2018-06-09
|
27
34
|
|
28
|
-
|
35
|
+
### Changed
|
29
36
|
|
30
37
|
- Relax dependency on ActiveSupport to work with 4.2 up to 5.X (Thanks to @iacobus! [See pull request](https://github.com/chaps-io/gush/pull/54))
|
31
38
|
|
32
39
|
|
33
40
|
## 1.1.0 - 2018-02-05
|
34
41
|
|
35
|
-
|
42
|
+
### Added
|
36
43
|
|
37
44
|
- Added ability to specify TTL for Redis keys and manually expire whole workflows (Thanks to @dmitrypol! [See pull request](https://github.com/chaps-io/gush/pull/48))
|
38
45
|
- Loosened dependency on redis-rb library to >= 3.2 and < 5.0 (Thanks to @mofumofu3n! [See pull request](https://github.com/chaps-io/gush/pull/52))
|
39
46
|
|
40
|
-
|
47
|
+
### Fixed
|
41
48
|
|
42
49
|
- Improved performance of (de)serializing workflows by not storing job array inside workflow JSON and other smaller improvements ([See pull request](https://github.com/chaps-io/gush/pull/53))
|
43
50
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
# Gush
|
2
|
-
|
3
|
-
## [![](http://i.imgur.com/ya8Wnyl.png)](https://chaps.io) proudly made by [Chaps](https://chaps.io)
|
1
|
+
# Gush
|
4
2
|
|
5
3
|
Gush is a parallel workflow runner using only Redis as storage and [ActiveJob](http://guides.rubyonrails.org/v4.2/active_job_basics.html#introduction) for scheduling and executing jobs.
|
6
4
|
|
@@ -10,14 +8,14 @@ Gush relies on directed acyclic graphs to store dependencies, see [Parallelizing
|
|
10
8
|
|
11
9
|
## **WARNING - version notice**
|
12
10
|
|
13
|
-
This README is about the `
|
11
|
+
This README is about the latest `master` code, which might differ from what is released on RubyGems. See tags to browse previous READMEs.
|
14
12
|
|
15
13
|
## Installation
|
16
14
|
|
17
15
|
### 1. Add `gush` to Gemfile
|
18
16
|
|
19
17
|
```ruby
|
20
|
-
gem 'gush', '~>
|
18
|
+
gem 'gush', '~> 2.0'
|
21
19
|
```
|
22
20
|
|
23
21
|
### 2. Create `Gushfile`
|
@@ -276,7 +274,7 @@ class EncodeVideo < Gush::Job
|
|
276
274
|
end
|
277
275
|
```
|
278
276
|
|
279
|
-
`payloads` is an array containing outputs from all ancestor jobs. So for our `
|
277
|
+
`payloads` is an array containing outputs from all ancestor jobs. So for our `EncodeVideo` job from above, the array will look like:
|
280
278
|
|
281
279
|
|
282
280
|
```ruby
|
@@ -323,6 +321,23 @@ it will generate a workflow with 5 `NotificationJob`s and one `AdminNotification
|
|
323
321
|
|
324
322
|
![DynamicWorkflow](https://i.imgur.com/HOI3fjc.png)
|
325
323
|
|
324
|
+
### Dynamic queue for jobs
|
325
|
+
|
326
|
+
There might be a case you want to configure different jobs in the workflow using different queues. Based on the above the example, we want to config `AdminNotificationJob` to use queue `admin` and `NotificationJob` use queue `user`.
|
327
|
+
|
328
|
+
```ruby
|
329
|
+
|
330
|
+
class NotifyWorkflow < Gush::Workflow
|
331
|
+
def configure(user_ids)
|
332
|
+
notification_jobs = user_ids.map do |user_id|
|
333
|
+
run NotificationJob, params: {user_id: user_id}, queue: 'user'
|
334
|
+
end
|
335
|
+
|
336
|
+
run AdminNotificationJob, after: notification_jobs, queue: 'admin'
|
337
|
+
end
|
338
|
+
end
|
339
|
+
```
|
340
|
+
|
326
341
|
## Command line interface (CLI)
|
327
342
|
|
328
343
|
### Checking status
|
@@ -348,9 +363,23 @@ This requires that you have imagemagick installed on your computer:
|
|
348
363
|
bundle exec gush viz <NameOfTheWorkflow>
|
349
364
|
```
|
350
365
|
|
366
|
+
### Customizing locking options
|
367
|
+
|
368
|
+
In order to prevent getting the RedisMutex::LockError error when having a large number of jobs, you can customize these 2 fields `locking_duration` and `polling_interval` as below
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
# config/initializers/gush.rb
|
372
|
+
Gush.configure do |config|
|
373
|
+
config.redis_url = "redis://localhost:6379"
|
374
|
+
config.concurrency = 5
|
375
|
+
config.locking_duration = 2 # how long you want to wait for the lock to be released, in seconds
|
376
|
+
config.polling_interval = 0.3 # how long the polling interval should be, in seconds
|
377
|
+
end
|
378
|
+
```
|
379
|
+
|
351
380
|
### Cleaning up afterwards
|
352
381
|
|
353
|
-
Running `NotifyWorkflow.create` inserts multiple keys into Redis every time it is ran. This data might be useful for analysis but at a certain point it can be purged via Redis TTL. By default gush and Redis will keep keys forever. To configure expiration you need to 2 things. Create initializer (specify config.ttl in seconds, be different per environment).
|
382
|
+
Running `NotifyWorkflow.create` inserts multiple keys into Redis every time it is ran. This data might be useful for analysis but at a certain point it can be purged via Redis TTL. By default gush and Redis will keep keys forever. To configure expiration you need to 2 things. Create initializer (specify config.ttl in seconds, be different per environment).
|
354
383
|
|
355
384
|
```ruby
|
356
385
|
# config/initializers/gush.rb
|
@@ -361,7 +390,7 @@ Gush.configure do |config|
|
|
361
390
|
end
|
362
391
|
```
|
363
392
|
|
364
|
-
And you need to call `flow.expire!` (optionally passing custom TTL value overriding `config.ttl`). This gives you control whether to expire data for specific workflow. Best NOT to set TTL to be too short (like minutes) but about a week in length. And you can run `Client.expire_workflow` and `Client.expire_job` passing appropriate IDs and TTL (pass -1 to NOT expire) values.
|
393
|
+
And you need to call `flow.expire!` (optionally passing custom TTL value overriding `config.ttl`). This gives you control whether to expire data for specific workflow. Best NOT to set TTL to be too short (like minutes) but about a week in length. And you can run `Client.expire_workflow` and `Client.expire_job` passing appropriate IDs and TTL (pass -1 to NOT expire) values.
|
365
394
|
|
366
395
|
### Avoid overlapping workflows
|
367
396
|
|
data/bin/gush
CHANGED
@@ -12,7 +12,7 @@ require 'gush'
|
|
12
12
|
begin
|
13
13
|
Gush::CLI.start(ARGV)
|
14
14
|
rescue Gush::WorkflowNotFound
|
15
|
-
puts "Workflow not found"
|
15
|
+
puts Paint["Workflow not found", :red]
|
16
16
|
rescue Gush::DependencyLevelTooDeep
|
17
|
-
puts "Dependency level too deep. Perhaps you have a dependency cycle?"
|
17
|
+
puts Paint["Dependency level too deep. Perhaps you have a dependency cycle?", :red]
|
18
18
|
end
|
data/gush.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "gush"
|
7
|
-
spec.version = "2.0
|
7
|
+
spec.version = "2.1.0"
|
8
8
|
spec.authors = ["Piotrek Okoński"]
|
9
9
|
spec.email = ["piotrek@okonski.org"]
|
10
10
|
spec.summary = "Fast and distributed workflow runner based on ActiveJob and Redis"
|
@@ -17,20 +17,19 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
-
spec.add_dependency "activejob", ">= 4.2.7", "<
|
21
|
-
spec.add_dependency "
|
20
|
+
spec.add_dependency "activejob", ">= 4.2.7", "< 7.1"
|
21
|
+
spec.add_dependency "concurrent-ruby", "~> 1.0"
|
22
22
|
spec.add_dependency "multi_json", "~> 1.11"
|
23
23
|
spec.add_dependency "redis", ">= 3.2", "< 5"
|
24
24
|
spec.add_dependency "redis-mutex", "~> 4.0.1"
|
25
25
|
spec.add_dependency "hiredis", "~> 0.6"
|
26
|
-
spec.add_dependency "
|
27
|
-
spec.add_dependency "terminal-table", "
|
28
|
-
spec.add_dependency "
|
29
|
-
spec.add_dependency "thor", "
|
26
|
+
spec.add_dependency "graphviz", "~> 1.2"
|
27
|
+
spec.add_dependency "terminal-table", ">= 1.4", "< 3.1"
|
28
|
+
spec.add_dependency "paint", "~> 2.2"
|
29
|
+
spec.add_dependency "thor", ">= 0.19", "< 1.3"
|
30
30
|
spec.add_dependency "launchy", "~> 2.4"
|
31
|
-
spec.add_development_dependency "bundler"
|
31
|
+
spec.add_development_dependency "bundler"
|
32
32
|
spec.add_development_dependency "rake", "~> 10.4"
|
33
33
|
spec.add_development_dependency "rspec", '~> 3.0'
|
34
34
|
spec.add_development_dependency "pry", '~> 0.10'
|
35
|
-
spec.add_development_dependency 'fakeredis', '~> 0.5'
|
36
35
|
end
|
data/lib/gush/cli/overview.rb
CHANGED
@@ -17,11 +17,11 @@ module Gush
|
|
17
17
|
elsif workflow.running?
|
18
18
|
running_status
|
19
19
|
elsif workflow.finished?
|
20
|
-
"done"
|
20
|
+
Paint["done", :green]
|
21
21
|
elsif workflow.stopped?
|
22
|
-
"stopped"
|
22
|
+
Paint["stopped", :red]
|
23
23
|
else
|
24
|
-
"ready to start"
|
24
|
+
Paint["ready to start", :blue]
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -48,10 +48,10 @@ module Gush
|
|
48
48
|
"ID" => workflow.id,
|
49
49
|
"Name" => workflow.class.to_s,
|
50
50
|
"Jobs" => workflow.jobs.count,
|
51
|
-
"Failed jobs" => failed_jobs_count
|
52
|
-
"Succeeded jobs" => succeeded_jobs_count
|
53
|
-
"Enqueued jobs" => enqueued_jobs_count
|
54
|
-
"Running jobs" => running_jobs_count
|
51
|
+
"Failed jobs" => Paint[failed_jobs_count, :red],
|
52
|
+
"Succeeded jobs" => Paint[succeeded_jobs_count, :green],
|
53
|
+
"Enqueued jobs" => Paint[enqueued_jobs_count, :yellow],
|
54
|
+
"Running jobs" => Paint[running_jobs_count, :blue],
|
55
55
|
"Remaining jobs" => remaining_jobs_count,
|
56
56
|
"Started at" => started_at,
|
57
57
|
"Status" => status
|
@@ -60,7 +60,7 @@ module Gush
|
|
60
60
|
|
61
61
|
def running_status
|
62
62
|
finished = succeeded_jobs_count.to_i
|
63
|
-
status = "running"
|
63
|
+
status = Paint["running", :yellow]
|
64
64
|
status += "\n#{finished}/#{total_jobs_count} [#{(finished*100)/total_jobs_count}%]"
|
65
65
|
end
|
66
66
|
|
@@ -69,7 +69,7 @@ module Gush
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def failed_status
|
72
|
-
status = "failed"
|
72
|
+
status = Paint["failed", :red]
|
73
73
|
status += "\n#{failed_job} failed"
|
74
74
|
end
|
75
75
|
|
@@ -77,13 +77,13 @@ module Gush
|
|
77
77
|
name = job.name
|
78
78
|
case
|
79
79
|
when job.failed?
|
80
|
-
"[✗] #{name
|
80
|
+
"[✗] #{Paint[name, :red]} \n"
|
81
81
|
when job.finished?
|
82
|
-
"[✓] #{name
|
82
|
+
"[✓] #{Paint[name, :green]} \n"
|
83
83
|
when job.enqueued?
|
84
|
-
"[•] #{name
|
84
|
+
"[•] #{Paint[name, :yellow]} \n"
|
85
85
|
when job.running?
|
86
|
-
"[•] #{name
|
86
|
+
"[•] #{Paint[name, :blue]} \n"
|
87
87
|
else
|
88
88
|
"[ ] #{name} \n"
|
89
89
|
end
|
data/lib/gush/cli.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'terminal-table'
|
2
|
-
require '
|
4
|
+
require 'paint'
|
3
5
|
require 'thor'
|
4
6
|
require 'launchy'
|
5
7
|
|
@@ -12,43 +14,45 @@ module Gush
|
|
12
14
|
def initialize(*)
|
13
15
|
super
|
14
16
|
Gush.configure do |config|
|
15
|
-
config.gushfile
|
16
|
-
config.concurrency
|
17
|
-
config.redis_url
|
18
|
-
config.namespace
|
19
|
-
config.ttl
|
17
|
+
config.gushfile = options.fetch("gushfile", config.gushfile)
|
18
|
+
config.concurrency = options.fetch("concurrency", config.concurrency)
|
19
|
+
config.redis_url = options.fetch("redis", config.redis_url)
|
20
|
+
config.namespace = options.fetch("namespace", config.namespace)
|
21
|
+
config.ttl = options.fetch("ttl", config.ttl)
|
22
|
+
config.locking_duration = options.fetch("locking_duration", config.locking_duration)
|
23
|
+
config.polling_interval = options.fetch("polling_interval", config.polling_interval)
|
20
24
|
end
|
21
25
|
load_gushfile
|
22
26
|
end
|
23
27
|
|
24
|
-
desc "create
|
28
|
+
desc "create WORKFLOW_CLASS", "Registers new workflow"
|
25
29
|
def create(name)
|
26
30
|
workflow = client.create_workflow(name)
|
27
31
|
puts "Workflow created with id: #{workflow.id}"
|
28
32
|
puts "Start it with command: gush start #{workflow.id}"
|
29
33
|
end
|
30
34
|
|
31
|
-
desc "start [
|
35
|
+
desc "start WORKFLOW_ID [ARG ...]", "Starts Workflow with given ID"
|
32
36
|
def start(*args)
|
33
37
|
id = args.shift
|
34
38
|
workflow = client.find_workflow(id)
|
35
39
|
client.start_workflow(workflow, args)
|
36
40
|
end
|
37
41
|
|
38
|
-
desc "create_and_start [
|
42
|
+
desc "create_and_start WORKFLOW_CLASS [ARG ...]", "Create and instantly start the new workflow"
|
39
43
|
def create_and_start(name, *args)
|
40
44
|
workflow = client.create_workflow(name)
|
41
45
|
client.start_workflow(workflow.id, args)
|
42
46
|
puts "Created and started workflow with id: #{workflow.id}"
|
43
47
|
end
|
44
48
|
|
45
|
-
desc "stop
|
49
|
+
desc "stop WORKFLOW_ID", "Stops Workflow with given ID"
|
46
50
|
def stop(*args)
|
47
51
|
id = args.shift
|
48
52
|
client.stop_workflow(id)
|
49
53
|
end
|
50
54
|
|
51
|
-
desc "show
|
55
|
+
desc "show WORKFLOW_ID", "Shows details about workflow with given ID"
|
52
56
|
option :skip_overview, type: :boolean
|
53
57
|
option :skip_jobs, type: :boolean
|
54
58
|
option :jobs, default: :all
|
@@ -60,7 +64,7 @@ module Gush
|
|
60
64
|
display_jobs_list_for(workflow, options[:jobs]) unless options[:skip_jobs]
|
61
65
|
end
|
62
66
|
|
63
|
-
desc "rm
|
67
|
+
desc "rm WORKFLOW_ID", "Delete workflow with given ID"
|
64
68
|
def rm(workflow_id)
|
65
69
|
workflow = client.find_workflow(workflow_id)
|
66
70
|
client.destroy_workflow(workflow)
|
@@ -81,13 +85,39 @@ module Gush
|
|
81
85
|
puts Terminal::Table.new(headings: headers, rows: rows)
|
82
86
|
end
|
83
87
|
|
84
|
-
desc "viz
|
85
|
-
|
88
|
+
desc "viz {WORKFLOW_CLASS|WORKFLOW_ID}", "Displays graph, visualising job dependencies"
|
89
|
+
option :filename, type: :string, default: nil
|
90
|
+
option :open, type: :boolean, default: nil
|
91
|
+
def viz(class_or_id)
|
86
92
|
client
|
87
|
-
|
88
|
-
|
93
|
+
|
94
|
+
begin
|
95
|
+
workflow = client.find_workflow(class_or_id)
|
96
|
+
rescue WorkflowNotFound
|
97
|
+
workflow = nil
|
98
|
+
end
|
99
|
+
|
100
|
+
unless workflow
|
101
|
+
begin
|
102
|
+
workflow = class_or_id.constantize.new
|
103
|
+
rescue NameError => e
|
104
|
+
STDERR.puts Paint["'#{class_or_id}' is not a valid workflow class or id", :red]
|
105
|
+
exit 1
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
opts = {}
|
110
|
+
|
111
|
+
if options[:filename]
|
112
|
+
opts[:filename], opts[:path] = File.split(options[:filename])
|
113
|
+
end
|
114
|
+
|
115
|
+
graph = Graph.new(workflow, **opts)
|
89
116
|
graph.viz
|
90
|
-
|
117
|
+
|
118
|
+
if (options[:open].nil? && !options[:filename]) || options[:open]
|
119
|
+
Launchy.open Pathname.new(graph.path).realpath.to_s
|
120
|
+
end
|
91
121
|
end
|
92
122
|
|
93
123
|
private
|
@@ -118,13 +148,14 @@ module Gush
|
|
118
148
|
|
119
149
|
def load_gushfile
|
120
150
|
file = client.configuration.gushfile
|
121
|
-
|
122
|
-
|
151
|
+
|
152
|
+
unless gushfile.exist?
|
153
|
+
raise Thor::Error, Paint["#{file} not found, please add it to your project", :red]
|
123
154
|
end
|
124
155
|
|
125
156
|
load file.to_s
|
126
157
|
rescue LoadError
|
127
|
-
raise Thor::Error, "failed to require #{file}"
|
158
|
+
raise Thor::Error, Paint["failed to require #{file}", :red]
|
128
159
|
end
|
129
160
|
end
|
130
161
|
end
|