kuroko2 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/kuroko2/definition_linker.js +1 -1
  3. data/app/assets/stylesheets/kuroko2/application.scss +4 -0
  4. data/app/controllers/kuroko2/api/job_instances_controller.rb +3 -2
  5. data/app/controllers/kuroko2/dashboard_controller.rb +1 -1
  6. data/app/controllers/kuroko2/job_definitions_controller.rb +2 -2
  7. data/app/controllers/kuroko2/job_instances_controller.rb +8 -18
  8. data/app/controllers/kuroko2/tokens_controller.rb +3 -3
  9. data/app/controllers/kuroko2/users_controller.rb +17 -1
  10. data/app/models/kuroko2/job_definition.rb +11 -0
  11. data/app/models/kuroko2/job_instance.rb +19 -2
  12. data/app/models/kuroko2/job_schedule.rb +3 -6
  13. data/app/models/kuroko2/job_suspend_schedule.rb +1 -1
  14. data/app/models/kuroko2/token.rb +8 -0
  15. data/app/views/kuroko2/execution_logs/index.json.jbuilder +1 -1
  16. data/app/views/kuroko2/job_definitions/_form.html.slim +6 -1
  17. data/app/views/kuroko2/job_definitions/_list.html.slim +12 -5
  18. data/app/views/kuroko2/job_definitions/_search_results.html.slim +10 -3
  19. data/app/views/kuroko2/job_definitions/show.html.slim +5 -3
  20. data/app/views/kuroko2/job_timelines/dataset.json.jbuilder +1 -1
  21. data/app/views/kuroko2/logs/index.html.slim +6 -6
  22. data/app/views/kuroko2/tokens/index.html.slim +2 -2
  23. data/app/views/kuroko2/users/edit.html.slim +37 -0
  24. data/app/views/kuroko2/users/show.html.slim +8 -4
  25. data/db/migrate/026_add_webhook_url_to_job_definitions.rb +5 -0
  26. data/lib/autoload/kuroko2/workflow/engine.rb +4 -6
  27. data/lib/autoload/kuroko2/workflow/notifier/concerns/chat_message_builder.rb +12 -0
  28. data/lib/autoload/kuroko2/workflow/notifier/hipchat.rb +30 -4
  29. data/lib/autoload/kuroko2/workflow/notifier/mail.rb +9 -1
  30. data/lib/autoload/kuroko2/workflow/notifier/slack.rb +31 -4
  31. data/lib/autoload/kuroko2/workflow/notifier/webhook.rb +173 -0
  32. data/lib/autoload/kuroko2/workflow/task/queue.rb +2 -2
  33. data/lib/autoload/kuroko2/workflow/task/sub_process.rb +2 -4
  34. data/lib/kuroko2/version.rb +1 -1
  35. data/spec/controllers/users_controller_spec.rb +51 -2
  36. data/spec/dummy/config/kuroko2.yml +2 -0
  37. data/spec/dummy/db/schema.rb +76 -92
  38. data/spec/dummy/log/development.log +1143 -0
  39. data/spec/dummy/log/test.log +271238 -0
  40. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-Q/-QhKaYdB1JJGAsq6Ih7uQZJD46XkY5Gw0-38DBDVg3Y.cache +1 -0
  41. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-h/-h4P8jVHGGfJVwG36J8kBUkHFa3HHGNiJQz0936uaxg.cache +1 -0
  42. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/24/24laeo7m53bkbst3Gxu4hlJY-EbnK-rQxH-DA4ujzwY.cache +1 -0
  43. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2e/2eEFzw4UUZHJizptl3nT5jVv3IL25_RdYImr3lAVlJ4.cache +1 -0
  44. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2z/2z8OmZrK1FFsPb8zq9RFli2IVM0gOna92hieZ4cK36c.cache +0 -0
  45. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4K/4Ky9Fg4qo8d_i8bJF6NOhDpxHuJ5kIX8n0w6C8wdHDU.cache +3 -0
  46. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Di/Di9ZEIp2OLO96tkqFN21AWfdoAhc0OCBOJb3o8RUk1I.cache +0 -0
  47. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ex/ExgjnrLZM8Hc_uT_sWVaQSNR26tGYCGUsbJDXs9GYO0.cache +1 -0
  48. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/FJ/FJW4oZDLKhsjg_UHdycQAY88BFtnMeeLCuArx6HIMdM.cache +0 -0
  49. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Iq/IqSpSELRWrOQtOK8F6mGZFPvfafM4yn8gB_VquH9E50.cache +1 -0
  50. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/JJ/JJ2dvNSAjiGkZZs_1Dz2TMWDJs4HypQ95b26cHN13I0.cache +1 -0
  51. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LJ/LJsVKu6GCC14s20BfJEDXwajK6-xWF72ANX5ONOTX1w.cache +1 -0
  52. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LL/LLCxb9El_km568UsA8DDOe8Vh3pPKE8IU6ZNww9ie8s.cache +1 -0
  53. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Pq/pqeS6zqHUdv-_25W2PSQMm31ql_cIpaK1iqEcfiNyUQ.cache +0 -0
  54. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Q9/Q9TwXzoqqs8Dm9v25gjZxYIkZW1UKm2X8g2koo5aYhQ.cache +1 -0
  55. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QJ/QJNiKbGgll2T_0mhQus6ZL9a2SM4Xqz7vs2V2KbELPw.cache +1 -0
  56. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QV/QVVeFw88kC-7HfzOk_dCVoFBnz9W_7-gmJFYh-Xlh-0.cache +0 -0
  57. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Qs/QsTn160WUaI8_u8tE8rz37XiSV9qLvSxiXAR-tCtV3Y.cache +0 -0
  58. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/V2/V2QhbjrEGa7in5Uj1P-3E1Ziw2AGno_ADefUhPNHw_A.cache +0 -0
  59. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Vj/VjICw6h8uQ_278ekFlu1znnPR8Gz1vWF_mRgy0KjZXs.cache +1 -0
  60. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/dH/dHFrKzzqtF3aoKs2wAI8z0CNHZoNuytfiHur9Zgz9z0.cache +1 -0
  61. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fE/fEFAQG1Uqt2e58VitSFoPsjVjntfPtgL9RKoKHUTS9U.cache +1 -0
  62. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fM/FMdA_jabowoG5SAWE93G7Hu8A-5GhfzC9Gjy3EJp1Ts.cache +1 -0
  63. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/hI/hIIciXZzgFWXdW0lamhs4r5zFFr4hnXvWAuOihCS5qI.cache +0 -0
  64. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/hW/hWOkA9ZbQJy1YfEXThjYPOiXRDVRgAeW8TmLm-uQCYk.cache +1 -0
  65. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/iv/ivrIChCv2olhH20VXJQTJgVWlx3t9ncsYxV0QfLT0Bs.cache +0 -0
  66. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/k3/k31T18tx4gR2rhpmDMYMLUa8KPDt7QRIR_qRK56LOdE.cache +0 -0
  67. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/oB/oB0c7AuqQVdgqJDgphXXOHw3SXqbDUYfZWxxm9-v_is.cache +0 -0
  68. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ou/ouMQatdL-PPhPVPw5o0xm5EBkVeVWLti06EUEVmfOBo.cache +1 -0
  69. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qM/qMZbagtANt1BI7qOJXWEpzxx1qa-IKMkyOy6EKEIIbE.cache +0 -0
  70. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/rc/rcceqGk009vh5_tK6Y-i1dvbYQwuUtRF888xZcnZrj8.cache +1 -0
  71. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sJ/sJOLo6McRe1YhfgIaGhcDaAoulIdYY7Rs07TAKmrSoY.cache +0 -0
  72. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sh/shGRyWpXjqxMTGB3As4Vibs8VGS0bZHHd4s0qabhwXI.cache +1 -0
  73. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sr/SRfo3vCtDVy0qd-OB9dv5a-xIVTHkJZDn8XwY_ymy7g.cache +1 -0
  74. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/vV/vV3Loym0NolgPoXFEVPOr5rDgB_Q5kvUA3InuEEvEvQ.cache +1 -0
  75. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wK/wK5S37PPHfwFm-4mrLMMPdOZ29-H75zo1T2gmErWjLI.cache +0 -0
  76. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wm/wm_qI7_LCxbnH6p7BK1Pqcocl-6TcULzTERICGZIdL0.cache +1 -0
  77. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zC/zCYIl3BglB_fMHME2oqK30CF97CBUG09R0ICLpE-pIM.cache +0 -0
  78. data/spec/features/dashborad_spec.rb +10 -3
  79. data/spec/features/users_spec.rb +20 -4
  80. data/spec/models/job_instance_spec.rb +1 -1
  81. data/spec/models/token_spec.rb +38 -0
  82. data/spec/workflow/notifier/hipchat_spec.rb +91 -0
  83. data/spec/workflow/notifier/mail_spec.rb +18 -2
  84. data/spec/workflow/notifier/slack_spec.rb +85 -0
  85. data/spec/workflow/notifier/webhook_spec.rb +187 -0
  86. data/spec/workflow/task/queue_spec.rb +11 -0
  87. metadata +93 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 82f8904d52f7ed97320ff851e35b91b5913d8baf
4
- data.tar.gz: c1fe3a881e302a1823a47aa37176756ae8de7470
3
+ metadata.gz: 05a36b6a990355277232fb05c8fee73420178657
4
+ data.tar.gz: ff0313b72bea3ff95c7961f92193ae7350cbee68
5
5
  SHA512:
6
- metadata.gz: 13794a4c4d2ceb7ae4ed9d38a1bc76fda67a853756c3cdc2a855141fab8d83fceb26b48de303747a0527e8c3cdef7d04e1748019892e436ad2253e074af0c776
7
- data.tar.gz: af34902e44039abf0efbdb912674a3196e8f7a7279aa968c09b4e0ba40270daeb2fe5a6c5e6eeaf6404593834d6a11e85d11acfcc75f7fa8fe11cd102ae972d7
6
+ metadata.gz: 94d255d97eed6354e37040ebff9c4bd2e4692c44f79bf3b7a9596a6ac5a12cd3c7b0585f3550b647b8453454a9b3d8352bc16427373576e03815761424b6df75
7
+ data.tar.gz: 9069f81f985f8b57b9885230be1eecfa6561f3fd0987afcfa041e4826f46560b89feb4817ea7b3832fbc90351cb84ab431cd115fbc1004f5edda3d4344feabdf
@@ -1,6 +1,6 @@
1
1
  jQuery(function ($) {
2
2
  function setDeifinitionLink(script) {
3
- script = script.replace(/sub_process:\s+(\d+)\s*\n/, function(match, jobId) {
3
+ script = script.replace(/sub_process:\s+(\d+)\s*$/gm, function(match, jobId) {
4
4
  return '<a href="/definitions/' + jobId + '">' + match + '</a>';
5
5
  });
6
6
 
@@ -13,6 +13,10 @@
13
13
  padding-top: 10px;
14
14
  }
15
15
 
16
+ .spacer-right-3 {
17
+ margin-right: 3px;
18
+ }
19
+
16
20
  .nowrap {
17
21
  white-space: nowrap;
18
22
  }
@@ -19,10 +19,11 @@ class Kuroko2::Api::JobInstancesController < Kuroko2::Api::ApplicationController
19
19
  raise HTTP::Forbidden.new("#{definition.name} is not allowed to be executed via API")
20
20
  end
21
21
 
22
- instance = definition.job_instances.create(
22
+ instance = definition.create_instance(
23
23
  script: definition.script.prepend(env_script),
24
+ launched_by: "instances API (#{basic_user_name})"
24
25
  )
25
- instance.logs.info("Launched by instances API (#{basic_user_name})")
26
+
26
27
  Kuroko2::Api::JobInstanceResource.new(instance)
27
28
  end
28
29
 
@@ -1,6 +1,6 @@
1
1
  class Kuroko2::DashboardController < Kuroko2::ApplicationController
2
2
  def index
3
- @definitions = current_user.job_definitions
3
+ @definitions = current_user.job_definitions.includes(:tags, :job_instances, :job_schedules)
4
4
 
5
5
  @input_tags = params[:tag] || []
6
6
  if @input_tags.present?
@@ -2,7 +2,7 @@ class Kuroko2::JobDefinitionsController < Kuroko2::ApplicationController
2
2
  before_action :set_definition, only: [:show, :edit, :update, :destroy]
3
3
 
4
4
  def index
5
- rel = Kuroko2::JobDefinition
5
+ rel = Kuroko2::JobDefinition.joins(:admins).includes(:tags, :job_instances, :job_schedules, :admins)
6
6
  query = query_params[:q]
7
7
 
8
8
  if query.present?
@@ -83,7 +83,7 @@ class Kuroko2::JobDefinitionsController < Kuroko2::ApplicationController
83
83
  end
84
84
 
85
85
  def definition_params
86
- params.require(:job_definition).permit(:name, :description, :script, :notify_cancellation, :hipchat_room, :hipchat_notify_finished, :suspended, :prevent_multi, :prevent_multi_on_failure, :hipchat_additional_text, :text_tags, :api_allowed, :slack_channel)
86
+ params.require(:job_definition).permit(:name, :description, :script, :notify_cancellation, :hipchat_room, :hipchat_notify_finished, :suspended, :prevent_multi, :prevent_multi_on_failure, :hipchat_additional_text, :text_tags, :api_allowed, :slack_channel, :webhook_url)
87
87
  end
88
88
 
89
89
  def query_params
@@ -9,24 +9,18 @@ class Kuroko2::JobInstancesController < Kuroko2::ApplicationController
9
9
  end
10
10
 
11
11
  def create
12
+ creation_params = { launched_by: current_user.name }
12
13
  if params[:job_definition].present?
13
- @instance = @definition.job_instances.create(params.require(:job_definition).permit(:script))
14
- else
15
- @instance = @definition.job_instances.create
14
+ creation_params.merge!(params.require(:job_definition).permit(:script).to_h.symbolize_keys)
16
15
  end
17
16
 
18
- if @instance
19
- @instance.logs.info("Launched by #{current_user.name}.")
20
-
21
- redirect_to job_definition_job_instance_path(@definition, @instance)
22
- else
23
- raise HTTP::BadRequest
24
- end
17
+ @instance = @definition.create_instance(creation_params)
18
+ redirect_to job_definition_job_instance_path(@definition, @instance)
25
19
  end
26
20
 
27
21
  def show
28
- @logs = @instance.logs
29
- @tokens = @instance.tokens
22
+ @logs = @instance.logs.order(:id)
23
+ @tokens = @instance.tokens.order(:id)
30
24
 
31
25
  if params[:mode] == :naked
32
26
  render partial: 'instance', layout: false
@@ -37,11 +31,7 @@ class Kuroko2::JobInstancesController < Kuroko2::ApplicationController
37
31
 
38
32
  def destroy
39
33
  if @instance.cancelable?
40
- ActiveRecord::Base.transaction { @instance.cancel }
41
-
42
- message = "This job was canceled by #{current_user.name}."
43
- @instance.logs.warn(message)
44
- Kuroko2.logger.warn(message)
34
+ ActiveRecord::Base.transaction { @instance.cancel(by: current_user.name) }
45
35
  end
46
36
 
47
37
  redirect_to job_definition_job_instance_path(@definition, @instance)
@@ -54,7 +44,7 @@ class Kuroko2::JobInstancesController < Kuroko2::ApplicationController
54
44
  execution.update_column(:execution_id, nil) if execution
55
45
  end
56
46
 
57
- @instance.cancel
47
+ @instance.cancel(by: current_user.name)
58
48
  end
59
49
 
60
50
  message = "Force canceled by #{current_user.name}."
@@ -14,12 +14,12 @@ class Kuroko2::TokensController < Kuroko2::ApplicationController
14
14
  def update
15
15
  @instance = @token.job_instance
16
16
 
17
- case params[:invoke]
18
- when 'skip'
17
+ case
18
+ when params[:invoke] == 'skip' && @token.skippable?
19
19
  @instance.logs.info("Skipped by #{current_user.name}.")
20
20
 
21
21
  @engine.skip(@token)
22
- when 'retry'
22
+ when params[:invoke] == 'retry' && @token.retryable?
23
23
  @instance.logs.info("Retry by #{current_user.name}.")
24
24
 
25
25
  @engine.retry(@token)
@@ -1,5 +1,6 @@
1
1
  class Kuroko2::UsersController < Kuroko2::ApplicationController
2
- before_action :set_user, only: [:destroy]
2
+ before_action :set_user, only: [:edit, :update, :destroy]
3
+ before_action :require_group_user, only: [:edit, :update, :destroy]
3
4
 
4
5
  def index
5
6
  @user = Kuroko2::User.new
@@ -23,6 +24,17 @@ class Kuroko2::UsersController < Kuroko2::ApplicationController
23
24
  @related_tags = @definitions.includes(:tags).map(&:tags).flatten.uniq
24
25
  end
25
26
 
27
+ def edit
28
+ end
29
+
30
+ def update
31
+ if @user.update(user_params)
32
+ redirect_to user_path(@user)
33
+ else
34
+ render action: :edit
35
+ end
36
+ end
37
+
26
38
  def create
27
39
  @user = Kuroko2::User.new(user_params)
28
40
  @user.provider = Kuroko2::User::GROUP_PROVIDER
@@ -59,4 +71,8 @@ class Kuroko2::UsersController < Kuroko2::ApplicationController
59
71
  def page_params
60
72
  params.permit(:page)
61
73
  end
74
+
75
+ def require_group_user
76
+ head :bad_request if @user.google_account?
77
+ end
62
78
  end
@@ -77,6 +77,7 @@ class Kuroko2::JobDefinition < Kuroko2::ApplicationRecord
77
77
  with: /\A#[^\.\s]+\z/, allow_blank: true,
78
78
  message: ' must start with # and must not include any dots or spaces'
79
79
  }
80
+ validates :webhook_url, format: { with: /\A#{URI::regexp(%w(http https))}\z/, allow_blank: true }
80
81
 
81
82
  def proceed_multi_instance?
82
83
  tokens = Kuroko2::Token.where(job_definition_id: self.id)
@@ -93,6 +94,16 @@ class Kuroko2::JobDefinition < Kuroko2::ApplicationRecord
93
94
  end
94
95
  end
95
96
 
97
+ def create_instance(script: nil, launched_by:, token: nil )
98
+ message = "Launched by #{launched_by}"
99
+
100
+ if token.present?
101
+ message = "(token #{token.uuid}) #{message}"
102
+ end
103
+
104
+ job_instances.create!(script: script, log_message: message)
105
+ end
106
+
96
107
  private
97
108
 
98
109
  def confirm_active_instances
@@ -3,6 +3,8 @@ class Kuroko2::JobInstance < Kuroko2::ApplicationRecord
3
3
 
4
4
  belongs_to :job_definition
5
5
 
6
+ attr_accessor :log_message
7
+
6
8
  has_many :logs, dependent: :delete_all do
7
9
  def info(message)
8
10
  add('INFO', message)
@@ -26,6 +28,7 @@ class Kuroko2::JobInstance < Kuroko2::ApplicationRecord
26
28
  has_one :memory_consumption_log, dependent: :destroy
27
29
 
28
30
  before_create :copy_script
31
+ after_create :notify_launch
29
32
  after_create :generate_token
30
33
 
31
34
  scope :working, -> { where(finished_at: nil, canceled_at: nil) }
@@ -43,10 +46,16 @@ class Kuroko2::JobInstance < Kuroko2::ApplicationRecord
43
46
  tokens.first.try(:cancelable?)
44
47
  end
45
48
 
46
- def cancel
49
+ def cancel(by:)
47
50
  self.tokens.destroy(*self.tokens)
48
51
  self.executions.destroy(*self.executions)
49
52
  self.touch(:canceled_at)
53
+
54
+ message = "This job was canceled by #{by}."
55
+ self.logs.warn(message)
56
+ Kuroko2.logger.warn(message)
57
+
58
+ Kuroko2::Workflow::Notifier.notify(:cancellation, self) if job_definition.hipchat_notify_finished?
50
59
  end
51
60
 
52
61
  # Log given value if it is greater than stored one.
@@ -84,6 +93,14 @@ class Kuroko2::JobInstance < Kuroko2::ApplicationRecord
84
93
  self.script = job_definition.try(:script) if self.script.blank?
85
94
  end
86
95
 
96
+ def notify_launch
97
+ if log_message
98
+ Kuroko2.logger.info(log_message)
99
+ self.logs.info(log_message)
100
+ Kuroko2::Workflow::Notifier.notify(:launch, self)
101
+ end
102
+ end
103
+
87
104
  def generate_token
88
105
  unless self.job_definition
89
106
  raise 'No parent association is found'
@@ -112,7 +129,7 @@ class Kuroko2::JobInstance < Kuroko2::ApplicationRecord
112
129
  self.logs.warn(message)
113
130
  Kuroko2.logger.warn(message)
114
131
 
115
- Kuroko2::Workflow::Notifier.notify(:cancellation, self)
132
+ Kuroko2::Workflow::Notifier.notify(:cancellation, self) if job_definition.notify_cancellation
116
133
  end
117
134
  end
118
135
  end
@@ -47,7 +47,7 @@ class Kuroko2::JobSchedule < Kuroko2::ApplicationRecord
47
47
  end
48
48
  end
49
49
 
50
- scheduled_times
50
+ scheduled_times.map(&:in_time_zone)
51
51
  end
52
52
 
53
53
  def suspend_times(time_from, time_to)
@@ -81,11 +81,8 @@ class Kuroko2::JobSchedule < Kuroko2::ApplicationRecord
81
81
  elsif suspend_times.include?(time)
82
82
  Kuroko2.logger.info("Skipped schedule suspended \"##{definition.id} #{definition.name}\" that is scheduled at #{I18n.l(time, format: :short)} by `#{schedule.cron}`")
83
83
  else
84
- message = "Launched \"##{definition.id} #{definition.name}\" that is scheduled at #{I18n.l(time, format: :short)} by `#{schedule.cron}`"
85
- Kuroko2.logger.info(message)
86
-
87
- instance = definition.job_instances.create
88
- instance.logs.info(message)
84
+ launched_by = "\"##{definition.id} #{definition.name}\" that is scheduled at #{I18n.l(time, format: :short)} by `#{schedule.cron}`"
85
+ definition.create_instance(launched_by: launched_by)
89
86
  end
90
87
  end
91
88
  end
@@ -19,7 +19,7 @@ class Kuroko2::JobSuspendSchedule < Kuroko2::ApplicationRecord
19
19
  end
20
20
  end
21
21
 
22
- suspend_times
22
+ suspend_times.map(&:in_time_zone)
23
23
  end
24
24
 
25
25
  private
@@ -90,6 +90,14 @@ class Kuroko2::Token < Kuroko2::ApplicationRecord
90
90
  end
91
91
  end
92
92
 
93
+ def skippable?
94
+ failure? || waiting?
95
+ end
96
+
97
+ def retryable?
98
+ failure?
99
+ end
100
+
93
101
  private
94
102
 
95
103
  def set_default_values
@@ -1,7 +1,7 @@
1
1
  json.token @response.next_forward_token
2
2
  json.events do
3
3
  json.array! @response.events do |event|
4
- json.timestamp l(Time.at(event.timestamp/1000), format: :short)
4
+ json.timestamp Time.at(event.timestamp/1000).in_time_zone
5
5
  begin
6
6
  log = JSON.parse(event.message)
7
7
  json.message rinku_auto_link(html_escape(log['message']), :urls)
@@ -32,14 +32,19 @@
32
32
 
33
33
  label Notification
34
34
  .form-group
35
+ label Hipchat Room Name
35
36
  = form.text_field :hipchat_room, class: 'form-control', placeholder: 'Hipchat Room name'
36
37
  .form-group
38
+ label Slack Channel
37
39
  = form.text_field :slack_channel, class: 'form-control', placeholder: '#slack-channel'
40
+ .form-group
41
+ label Webhook URL
42
+ = form.text_field :webhook_url, class: 'form-control', placeholder: 'http://example.com/webhook/endpoint'
38
43
 
39
44
  .checkbox
40
45
  label
41
46
  = form.check_box :hipchat_notify_finished
42
- ' Notify success event to Slack/Hipchat
47
+ ' Notify all event to Slack/Hipchat/Webhook
43
48
 
44
49
  .checkbox
45
50
  label
@@ -4,9 +4,9 @@
4
4
  tr
5
5
  th #
6
6
  th.col-md-3 Name
7
- th.col-md-3 Next Job
8
- th.col-md-2 Latest Status
9
- th.col-md-8 data-defaultsort='disabled' Description
7
+ th.col-md-2 Next Job
8
+ th.col-md-1 Latest Status
9
+ th.col-md-5 data-defaultsort='disabled' Tags / Description
10
10
  th.col-md-1 data-defaultsort='disabled' &nbsp;
11
11
  tbody
12
12
  - for definition in definitions
@@ -19,8 +19,15 @@
19
19
  - else
20
20
  td data-value="9999999999" --
21
21
  td= labeled_status(definition.job_instances.take)
22
- td= first_line(definition.description)
23
22
  td
24
- = link_to raw('<i class="fa fa-chevron-right"></i> View Details'), definition, class: 'btn btn-sm btn-default'
23
+ - definition.tags.each do |tag|
24
+ =link_to tag.name, { 'tag': [tag.name] }, class: 'label label-default spacer-right-3'
25
+ = first_line(definition.description)
26
+ td
27
+ = link_to definition, class: 'btn btn-sm btn-default' do
28
+ i class="fa fa-chevron-right"
29
+ | &nbsp;
30
+ span class="small" View Details
31
+
25
32
  - else
26
33
  .text-muted.well.well-sm.no-shadow There are no favorite job definitions.
@@ -26,7 +26,7 @@
26
26
  th #
27
27
  th.col-md-3 Name
28
28
  th.col-md-3 Administrators
29
- th.col-md-5 Description
29
+ th.col-md-5 Tags / Description
30
30
  th.col-md-1 &nbsp;
31
31
  - for definition in definitions
32
32
  tr
@@ -39,9 +39,16 @@
39
39
  - definition.admins.each do |user|
40
40
  = link_to user.name, user_path(user)
41
41
  br
42
- td= first_line(definition.description)
43
42
  td
44
- = link_to raw('<i class="fa fa-chevron-right"></i> View Details'), definition, class: 'btn btn-sm btn-default'
43
+ - definition.tags.each do |tag|
44
+ =link_to tag.name, job_definitions_path('tag': [tag.name]), class: 'label label-default spacer-right-3'
45
+ = first_line(definition.description)
46
+ td
47
+ = link_to definition, class: 'btn btn-sm btn-default' do
48
+ i class="fa fa-chevron-right"
49
+ | &nbsp;
50
+ span class="small" View Details
51
+
45
52
  - else
46
53
  - if params[:q].present?
47
54
  .text-muted.well.well-sm.no-shadow No results found for the query.
@@ -19,7 +19,7 @@
19
19
 
20
20
  h4= 'Tags'
21
21
  - for tag in @definition.tags
22
- =link_to tag.name, job_definitions_path(tag: [tag.name]), class: 'badge'
22
+ =link_to tag.name, job_definitions_path(tag: [tag.name]), class: 'label label-default spacer-right-3'
23
23
 
24
24
  h3= 'Administrator'.pluralize(@definition.admins.count)
25
25
  ul.media-list
@@ -43,16 +43,18 @@
43
43
  - if @definition.hipchat_room.present? || @definition.slack_channel.present?
44
44
  - if @definition.hipchat_notify_finished?
45
45
  li
46
- 'Notify all event to Slack/Hipchat
46
+ 'Notify all event to Slack/Hipchat/Webhook
47
47
  ul
48
+ li webhook url: #{@definition.webhook_url}
48
49
  li hipchat room: #{@definition.hipchat_room}
49
50
  li slack channel: #{@definition.slack_channel}
50
51
  - if @definition.hipchat_additional_text
51
52
  li Failure notification text: #{@definition.hipchat_additional_text}
52
53
  - else
53
54
  li
54
- 'Notify failure event to Slack/Hipchat
55
+ 'Notify failure event to Slack/Hipchat/Webhook
55
56
  ul
57
+ li webhook url: #{@definition.webhook_url}
56
58
  li hipchat room: #{@definition.hipchat_room}
57
59
  li slack channel: #{@definition.slack_channel}
58
60
  - if @definition.hipchat_additional_text
@@ -5,7 +5,7 @@ json.data do
5
5
  json.id instance.id
6
6
  json.content "<a href='#{job_definition_job_instance_path(instance.job_definition, instance)}'>##{instance.job_definition.id} #{instance.job_definition.name}</a>"
7
7
  json.start instance.created_at.strftime('%Y-%m-%d %H:%M:%S')
8
- json.end (instance.error_at || instance.canceled_at || instance.finished_at).try!(:strftime, '%Y-%m-%d %H:%M:%S')
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
10
10
  end
11
11
  end