kuroko2 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
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