kuroko2 0.4.3 → 0.4.4

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/app/controllers/kuroko2/api/application_controller.rb +4 -0
  4. data/app/controllers/kuroko2/api/job_definitions_controller.rb +64 -0
  5. data/app/controllers/kuroko2/job_definitions_controller.rb +9 -2
  6. data/app/errors/http/unprocessable_entity.rb +4 -0
  7. data/app/models/kuroko2/api/job_definition_resource.rb +11 -0
  8. data/app/models/kuroko2/job_definition.rb +1 -1
  9. data/app/views/kuroko2/job_definitions/_alert.html.slim +1 -1
  10. data/app/views/kuroko2/job_definitions/_list.html.slim +4 -1
  11. data/app/views/kuroko2/job_definitions/_search_results.html.slim +4 -1
  12. data/app/views/kuroko2/job_definitions/show.html.slim +4 -2
  13. data/app/views/kuroko2/job_timelines/dataset.json.jbuilder +1 -1
  14. data/app/views/kuroko2/users/index.html.slim +1 -1
  15. data/config/routes.rb +2 -2
  16. data/db/migrate/030_add_notify_back_to_normal.rb +5 -0
  17. data/lib/autoload/kuroko2/workflow/engine.rb +6 -2
  18. data/lib/autoload/kuroko2/workflow/notifier/concerns/chat_message_builder.rb +4 -0
  19. data/lib/autoload/kuroko2/workflow/notifier/hipchat.rb +5 -0
  20. data/lib/autoload/kuroko2/workflow/notifier/mail.rb +4 -0
  21. data/lib/autoload/kuroko2/workflow/notifier/slack.rb +7 -0
  22. data/lib/autoload/kuroko2/workflow/notifier/webhook.rb +10 -0
  23. data/lib/kuroko2/version.rb +1 -1
  24. data/spec/controllers/job_definitions_controller_spec.rb +62 -0
  25. data/spec/dummy/db/schema.rb +133 -132
  26. data/spec/dummy/log/test.log +667 -0
  27. data/spec/features/job_instance_spec.rb +4 -5
  28. data/spec/requests/api/job_definitions_spec.rb +178 -0
  29. data/spec/workflow/engine_spec.rb +2 -0
  30. data/spec/workflow/notifier/hipchat_spec.rb +11 -0
  31. data/spec/workflow/notifier/mail_spec.rb +8 -0
  32. data/spec/workflow/notifier/slack_spec.rb +9 -0
  33. data/spec/workflow/notifier/webhook_spec.rb +11 -0
  34. metadata +9 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe10912ca61191700c1d3e4d3bc23f1f4e29faa6
4
- data.tar.gz: 9651a35f813987706a7f21dd0cfda78e24dd9eef
3
+ metadata.gz: 80baa8f9a1ca15294cc73f9f726f5584433d6acb
4
+ data.tar.gz: 57be564404077de0d32b829687cc579ee925a02f
5
5
  SHA512:
6
- metadata.gz: 5925f797d1a86c93ea05a536c259eef76b2eb88ef784dc35447747ee0264978e3acc350055222994033c1dcb20c8282ec0f41982870155bcf38f9b1ec3ece6bc
7
- data.tar.gz: 7f59ae45fd8dfd1d3b0b72ebcb7487c8a27d6a70f9d29e2258b2510f0cedce61e1852c14c4938b0168b9a244de4f764f74f40bf7c21c6a5d03a39d85e3ac1a30
6
+ metadata.gz: 7e657c7824576cecaa2e3cbc2a01abdad723efe66f4dd6da7fa0fe4f68f215f8f46dc3ca3ed7982bb79fb299d736d2363dda21846e604aa61e5c8df03dde934f
7
+ data.tar.gz: 296957b071325388c8407d6dabeaabe85b1d6ce1498db6f0d80af9eefb4ed2c161c2e17f5592978057189751d5809b579bcfb00e84ccf040329b20594f7513b3
data/README.md CHANGED
@@ -37,6 +37,7 @@ Documentation is available at [docs/index.md](docs/index.md).
37
37
  - winebarrel
38
38
  - t8m8
39
39
  - yohfee
40
+ - takonomura
40
41
 
41
42
  ## License
42
43
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -15,6 +15,10 @@ class Kuroko2::Api::ApplicationController < ActionController::Base
15
15
  respond_with_error(401, 'unauthorized', exception.message)
16
16
  end
17
17
 
18
+ rescue_from HTTP::UnprocessableEntity do |exception|
19
+ respond_with_error(422, 'unprocessable_entity', exception.message)
20
+ end
21
+
18
22
  rescue_from WeakParameters::ValidationError do |exception|
19
23
  respond_with_error(400, 'bad_request', exception.message)
20
24
  end
@@ -0,0 +1,64 @@
1
+ class Kuroko2::Api::JobDefinitionsController < Kuroko2::Api::ApplicationController
2
+ include Garage::RestfulActions
3
+
4
+ private
5
+
6
+ def require_resources
7
+ end
8
+
9
+ def create_resource
10
+ definition = Kuroko2::JobDefinition.new(definition_params(params))
11
+ user_ids = admin_id_params(params)
12
+ definition.admins = Kuroko2::User.active.with(user_ids)
13
+
14
+ if definition.save
15
+ definition.admins.each do |user|
16
+ user.stars.create(job_definition: definition) if user.google_account?
17
+ end
18
+
19
+ @resource = Kuroko2::Api::JobDefinitionResource.new(definition)
20
+ else
21
+ raise HTTP::UnprocessableEntity.new("#{definition.name}: #{definition.errors.full_messages.join()}")
22
+ end
23
+ end
24
+
25
+ def require_resource
26
+ definition = Kuroko2::JobDefinition.find(params[:id])
27
+ @resource = Kuroko2::Api::JobDefinitionResource.new(definition)
28
+ end
29
+
30
+ def update_resource
31
+ definition = Kuroko2::JobDefinition.find(params[:id])
32
+
33
+ if definition.update(definition_params(params))
34
+ @resource = Kuroko2::Api::JobDefinitionResource.new(definition)
35
+ else
36
+ raise HTTP::UnprocessableEntity.new("#{definition.name}: #{definition.errors.full_messages.join()}")
37
+ end
38
+ end
39
+
40
+ def definition_params(params)
41
+ params.permit(
42
+ :name,
43
+ :description,
44
+ :script,
45
+ :notify_cancellation,
46
+ :hipchat_room,
47
+ :hipchat_notify_finished,
48
+ :suspended,
49
+ :prevent_multi,
50
+ :prevent_multi_on_failure,
51
+ :hipchat_additional_text,
52
+ :text_tags,
53
+ :api_allowed,
54
+ :slack_channel,
55
+ :webhook_url)
56
+ end
57
+
58
+ def admin_id_params(params)
59
+ params.permit(user_id: []).
60
+ try!(:[], :user_id).
61
+ try!(:reject, &:blank?).
62
+ try!(:map, &:to_i) || []
63
+ end
64
+ end
@@ -33,8 +33,15 @@ class Kuroko2::JobDefinitionsController < Kuroko2::ApplicationController
33
33
  end
34
34
 
35
35
  def new
36
- @definition = Kuroko2::JobDefinition.new
37
- @definition.admins << current_user
36
+ dup_from = Kuroko2::JobDefinition.find_by(id: params[:dup_from])
37
+ if dup_from.present?
38
+ @definition = dup_from.dup
39
+ @definition.admins = dup_from.admins
40
+ @definition.tags = dup_from.tags
41
+ else
42
+ @definition = Kuroko2::JobDefinition.new
43
+ end
44
+ @definition.admins << current_user unless @definition.admins.include?(current_user)
38
45
  end
39
46
 
40
47
  def create
@@ -0,0 +1,4 @@
1
+ module HTTP
2
+ class UnprocessableEntity < StandardError
3
+ end
4
+ end
@@ -0,0 +1,11 @@
1
+ class Kuroko2::Api::JobDefinitionResource < Kuroko2::Api::ApplicationResource
2
+ property :id
3
+
4
+ property :name
5
+
6
+ property :description
7
+
8
+ property :script
9
+
10
+ delegate :id, :name, :description, :script, to: :model
11
+ end
@@ -81,7 +81,7 @@ class Kuroko2::JobDefinition < Kuroko2::ApplicationRecord
81
81
  end
82
82
 
83
83
  def text_tags
84
- tags.pluck(:name).join(',')
84
+ tags.map(&:name).join(',')
85
85
  end
86
86
 
87
87
  def text_tags=(text_tags)
@@ -1,7 +1,7 @@
1
1
  - if @definition.errors.any?
2
2
  .alert.alert-danger
3
3
  i.fa.fa-ban
4
- h4 #{pluralize(@definition.errors.count, "error")} prohibited this employee from being saved:
4
+ h4 #{pluralize(@definition.errors.count, "error")} prohibited this job definition from being saved:
5
5
  ul
6
6
  - @definition.errors.full_messages.each do |message|
7
7
  li= message
@@ -12,7 +12,10 @@
12
12
  - for definition in definitions
13
13
  tr
14
14
  td= definition.id
15
- td.no-decorate= link_to definition.name, definition
15
+ td.no-decorate
16
+ - if definition.suspended
17
+ span.label.label-warning.spacer-right-3 SUSPENDED
18
+ = link_to definition.name, definition
16
19
  - if !definition.suspended? && !definition.job_schedules.empty?
17
20
  - next_job_schedule = definition.job_schedules.map(&:next).min
18
21
  - if next_job_schedule
@@ -34,7 +34,10 @@
34
34
  span.star-holder
35
35
  = star_link_for(definition)
36
36
  td= definition.id
37
- td.no-decorate= link_to definition.name, definition
37
+ td.no-decorate
38
+ - if definition.suspended
39
+ span.label.label-warning.spacer-right-3 SUSPENDED
40
+ = link_to definition.name, definition
38
41
  td.no-decorate
39
42
  - definition.admins.each do |user|
40
43
  = link_to user.name, user_path(user)
@@ -80,9 +80,11 @@
80
80
 
81
81
  .box-footer
82
82
  .row
83
- .col-md-6
83
+ .col-md-4
84
84
  = link_to 'Edit Job definition', edit_job_definition_path(@definition), class: 'btn btn-default btn-block', role: 'button'
85
- .col-md-6
85
+ .col-md-4
86
+ = link_to 'Duplicate Job definition', new_job_definition_path(dup_from: @definition.id), class: 'btn btn-default btn-block', role: 'button'
87
+ .col-md-4
86
88
  = link_to 'Destroy Job definition', @definition, method: :delete, class: 'btn btn-default btn-block', role: 'button', data: { confirm: 'Are you sure?' }
87
89
  .col-md-5#schedules-holder
88
90
  = render template: 'kuroko2/job_schedules/index'
@@ -3,7 +3,7 @@ json.end @end_at.strftime('%Y-%m-%d %H:%M:%S')
3
3
  json.data do
4
4
  json.array! @instances do |instance|
5
5
  json.id instance.id
6
- json.content "<a href='#{job_definition_job_instance_path(instance.job_definition, instance)}'>##{instance.job_definition.id} #{instance.job_definition.name}</a>"
6
+ json.content "<a href='#{job_definition_job_instance_path(instance.job_definition, instance)}'>##{instance.job_definition.id} #{html_escape(instance.job_definition.name)}</a>"
7
7
  json.start instance.created_at.strftime('%Y-%m-%d %H:%M:%S')
8
8
  json.end (instance.error_at || instance.canceled_at || instance.finished_at || Time.current).try!(:strftime, '%Y-%m-%d %H:%M:%S')
9
9
  json.group instance.job_definition.id
@@ -16,7 +16,7 @@
16
16
  - if @user.errors.any?
17
17
  .alert.alert-danger
18
18
  i.fa.fa-ban
19
- h4 #{pluralize(@user.errors.count, "error")} prohibited this employee from being saved:
19
+ h4 #{pluralize(@user.errors.count, "error")} prohibited this user from being saved:
20
20
  ul
21
21
  - @user.errors.full_messages.each do |message|
22
22
  li= message
data/config/routes.rb CHANGED
@@ -42,8 +42,8 @@ Kuroko2::Engine.routes.draw do
42
42
  get '/osd' => 'dashboard#osd', as: :osd
43
43
 
44
44
  scope :v1, module: 'api', as: 'api' do
45
- resources :job_definitions, path: 'definitions', only: [] do
46
- resources :job_instances, path: 'instances', only: [:show, :create]
45
+ resources :job_definitions, path: 'definitions', only: %w(create show update) do
46
+ resources :job_instances, path: 'instances', only: %w(show create)
47
47
  end
48
48
 
49
49
  namespace :stats do
@@ -0,0 +1,5 @@
1
+ class AddNotifyBackToNormal < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :job_instances, :retrying, :boolean, default: false, null: false
4
+ end
5
+ end
@@ -25,7 +25,7 @@ module Kuroko2
25
25
  node = extract_node(token)
26
26
 
27
27
  message = "(token #{token.uuid}) Retry current node: '#{node.type}: #{node.option}'"
28
- token.job_instance.update_column(:error_at, nil)
28
+ token.job_instance.update_columns(error_at: nil, retrying: true)
29
29
  token.job_instance.logs.info(message)
30
30
 
31
31
  token.mark_as_working
@@ -119,7 +119,11 @@ module Kuroko2
119
119
  token.mark_as_finished
120
120
  unless token.parent
121
121
  token.job_instance.touch(:finished_at)
122
- Notifier.notify(:finished, token.job_instance)
122
+ if token.job_instance.retrying?
123
+ Notifier.notify(:back_to_normal, token.job_instance)
124
+ else
125
+ Notifier.notify(:finished, token.job_instance)
126
+ end
123
127
  token.destroy!
124
128
  end
125
129
  end
@@ -20,6 +20,10 @@ module Kuroko2
20
20
  "Launched '#{@definition.name}'"
21
21
  end
22
22
 
23
+ def back_to_normal_text
24
+ "Backed to normal '#{@definition.name}'"
25
+ end
26
+
23
27
  def retrying_text
24
28
  "Retrying the current task in '#{@definition.name}'"
25
29
  end
@@ -79,6 +79,11 @@ module Kuroko2
79
79
  end
80
80
  end
81
81
 
82
+ def notify_back_to_normal
83
+ message = build_message(level: 'SUCCESS', text: message_builder.back_to_normal_text)
84
+ send_to_hipchat(message)
85
+ end
86
+
82
87
  def notify_long_elapsed_time
83
88
  message = build_message(level: 'WARNING', text: message_builder.long_elapsed_time_text)
84
89
  send_to_hipchat(message, color: 'red')
@@ -37,6 +37,10 @@ module Kuroko2
37
37
  # do nothing
38
38
  end
39
39
 
40
+ def notify_back_to_normal
41
+ # do nothing
42
+ end
43
+
40
44
  def notify_long_elapsed_time
41
45
  Kuroko2::Notifications.notify_long_elapsed_time(@job_instance).deliver_now
42
46
  end
@@ -88,6 +88,13 @@ module Kuroko2
88
88
  end
89
89
  end
90
90
 
91
+ def notify_back_to_normal
92
+ send_attachment_message_to_slack(
93
+ level: 'SUCCESS',
94
+ text: message_builder.back_to_normal_text,
95
+ )
96
+ end
97
+
91
98
  def notify_long_elapsed_time
92
99
  send_attachment_message_to_slack(
93
100
  level: 'WARNING',
@@ -100,6 +100,16 @@ module Kuroko2
100
100
  end
101
101
  end
102
102
 
103
+ def notify_back_to_normal
104
+ request(
105
+ build_payload(
106
+ action: 'notify_back_to_normal',
107
+ level: 'SUCCESS',
108
+ subject: message_builder.back_to_normal_text,
109
+ )
110
+ )
111
+ end
112
+
103
113
  def notify_long_elapsed_time
104
114
  request(
105
115
  build_payload(
@@ -1,3 +1,3 @@
1
1
  module Kuroko2
2
- VERSION = '0.4.3'
2
+ VERSION = '0.4.4'
3
3
  end
@@ -38,6 +38,68 @@ describe Kuroko2::JobDefinitionsController do
38
38
 
39
39
  expect(assigns(:definition)).to be_new_record
40
40
  end
41
+
42
+ context 'with dup_from params' do
43
+ subject! { get :new, params: { dup_from: definition.id } }
44
+ it do
45
+ expect(response).to have_http_status(:ok)
46
+ expect(response).to render_template('new')
47
+
48
+ expect(assigns(:definition)).to be_new_record
49
+ expect(assigns(:definition).name).to eq definition.name
50
+ expect(assigns(:definition).admins).to eq definition.admins + [controller.current_user]
51
+ expect(assigns(:definition).tags).to eq definition.tags
52
+ end
53
+
54
+ context 'with current_user and another admin user' do
55
+ let!(:admin_user) { create(:user) }
56
+ let!(:definition) { create(:job_definition, admins: [admin_user, controller.current_user]) }
57
+ it do
58
+ expect(response).to have_http_status(:ok)
59
+ expect(response).to render_template('new')
60
+
61
+ expect(assigns(:definition)).to be_new_record
62
+ expect(assigns(:definition).name).to eq definition.name
63
+ expect(assigns(:definition).admins).to match_array [admin_user, controller.current_user]
64
+ end
65
+
66
+ context 'with only another admin user' do
67
+ let!(:definition) { create(:job_definition, admins: [admin_user]) }
68
+ it do
69
+ expect(response).to have_http_status(:ok)
70
+ expect(response).to render_template('new')
71
+
72
+ expect(assigns(:definition)).to be_new_record
73
+ expect(assigns(:definition).name).to eq definition.name
74
+ expect(assigns(:definition).admins).to match_array [admin_user, controller.current_user]
75
+ end
76
+ end
77
+ end
78
+
79
+ context 'with tags' do
80
+ let!(:definition) { create(:job_definition, text_tags: 'First,Second') }
81
+ it do
82
+ expect(response).to have_http_status(:ok)
83
+ expect(response).to render_template('new')
84
+
85
+ expect(assigns(:definition)).to be_new_record
86
+ expect(assigns(:definition).name).to eq definition.name
87
+ expect(assigns(:definition).text_tags).to eq definition.text_tags
88
+ end
89
+ end
90
+
91
+ context 'with invalid id' do
92
+ subject! { get :new, params: { dup_from: 'invalid' } }
93
+ it do
94
+ expect(response).to have_http_status(:ok)
95
+ expect(response).to render_template('new')
96
+
97
+ expect(assigns(:definition)).to be_new_record
98
+ expect(assigns(:definition).name).to be_blank
99
+ expect(assigns(:definition).admins).to eq [controller.current_user]
100
+ end
101
+ end
102
+ end
41
103
  end
42
104
 
43
105
  describe '#create' do