shipit-engine 0.8.9 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/shipit_bs.js.coffee +2 -0
  3. data/app/assets/javascripts/task.js.coffee +14 -5
  4. data/app/assets/javascripts/task/search_bar.js.coffee +52 -0
  5. data/app/assets/javascripts/task/stream.js.coffee +9 -2
  6. data/app/assets/javascripts/task/tty.js.coffee +75 -28
  7. data/app/assets/stylesheets/_base/_forms.scss +5 -0
  8. data/app/assets/stylesheets/_pages/_commits.scss +1 -1
  9. data/app/assets/stylesheets/_pages/_deploy.scss +56 -24
  10. data/app/assets/stylesheets/_pages/_settings.scss +5 -0
  11. data/app/assets/stylesheets/_structure/_layout.scss +1 -0
  12. data/app/assets/stylesheets/_structure/_main.scss +4 -0
  13. data/app/assets/stylesheets/shipit.scss +2 -0
  14. data/app/assets/stylesheets/shipit_bs.scss +22 -0
  15. data/app/controllers/shipit/deploys_controller.rb +5 -1
  16. data/app/controllers/shipit/shipit_controller.rb +10 -3
  17. data/app/controllers/shipit/stacks_controller.rb +12 -3
  18. data/app/controllers/shipit/tasks_controller.rb +4 -0
  19. data/app/helpers/shipit/shipit_helper.rb +18 -0
  20. data/app/helpers/shipit/stacks_helper.rb +1 -1
  21. data/app/jobs/shipit/cache_deploy_spec_job.rb +2 -0
  22. data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -0
  23. data/app/jobs/shipit/git_mirror_update_job.rb +2 -0
  24. data/app/jobs/shipit/perform_task_job.rb +1 -0
  25. data/app/models/shipit/commit.rb +2 -2
  26. data/app/models/shipit/deploy.rb +1 -1
  27. data/app/models/shipit/deploy_spec/bundler_discovery.rb +1 -1
  28. data/app/models/shipit/duration.rb +28 -0
  29. data/app/models/shipit/stack.rb +33 -11
  30. data/app/models/shipit/task.rb +26 -3
  31. data/app/serializers/shipit/task_serializer.rb +14 -1
  32. data/app/views/bootstrap/shipit/missing_settings.html.erb +97 -0
  33. data/app/views/bootstrap/shipit/stacks/new.html.erb +44 -0
  34. data/app/views/layouts/shipit.html.erb +1 -1
  35. data/app/views/layouts/shipit_bootstrap.html.erb +44 -0
  36. data/app/views/shipit/commits/_commit.html.erb +3 -2
  37. data/app/views/shipit/deploys/_deploy.html.erb +11 -2
  38. data/app/views/shipit/deploys/show.html.erb +1 -1
  39. data/app/views/shipit/stacks/new.html.erb +12 -12
  40. data/app/views/shipit/stacks/settings.html.erb +5 -0
  41. data/app/views/shipit/stacks/show.html.erb +1 -1
  42. data/app/views/shipit/tasks/_task.html.erb +10 -2
  43. data/app/views/shipit/tasks/_task_output.html.erb +11 -1
  44. data/app/views/shipit/tasks/show.html.erb +1 -1
  45. data/config/routes.rb +1 -0
  46. data/db/migrate/20160324155046_add_started_at_and_ended_at_on_tasks.rb +25 -0
  47. data/lib/shipit.rb +13 -0
  48. data/lib/shipit/command.rb +13 -9
  49. data/lib/shipit/engine.rb +8 -0
  50. data/lib/shipit/template_renderer_extension.rb +16 -0
  51. data/lib/shipit/version.rb +1 -1
  52. data/test/controllers/deploys_controller_test.rb +11 -0
  53. data/test/controllers/stacks_controller_test.rb +5 -0
  54. data/test/controllers/tasks_controller_test.rb +6 -0
  55. data/test/dummy/config/secrets.example.yml +4 -0
  56. data/test/dummy/config/secrets.yml +2 -0
  57. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/bar.txt +2 -0
  58. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/dkfdsf +0 -0
  59. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/dskjfsd +0 -0
  60. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/dslkjfjsdf +0 -0
  61. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/plopfizz +0 -0
  62. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/sd +0 -0
  63. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/sdkfjsdf +1 -0
  64. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/sdlfjsdfdsfj +0 -0
  65. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/sdlkfjsdlkfjsdlkfjdsfsdfksdfjsldkfjsdlkfjsdf +0 -0
  66. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/shipit.yml +32 -0
  67. data/test/dummy/data/stacks/byroot/junk/production/deploys/83/toto.txt +2 -0
  68. data/test/dummy/data/stacks/byroot/junk/production/git/bar.txt +1 -0
  69. data/test/dummy/data/stacks/byroot/junk/production/git/shipit.yml +6 -1
  70. data/test/dummy/data/stacks/byroot/test/production/git/README.md +1 -0
  71. data/test/dummy/db/development.sqlite3 +0 -0
  72. data/test/dummy/db/schema.rb +3 -1
  73. data/test/dummy/db/seeds.rb +6 -0
  74. data/test/dummy/db/test.sqlite3 +0 -0
  75. data/test/dummy/db/test.sqlite3-journal +0 -0
  76. data/test/fixtures/shipit/tasks.yml +11 -0
  77. data/test/models/commits_test.rb +1 -1
  78. data/test/models/deploys_test.rb +40 -0
  79. data/test/models/duration_test.rb +13 -0
  80. data/test/models/stacks_test.rb +3 -4
  81. data/test/unit/command_test.rb +14 -0
  82. data/vendor/assets/javascripts/clusterize.js +327 -0
  83. data/vendor/assets/javascripts/mousetrap-global-bind.js +43 -0
  84. data/vendor/assets/javascripts/mousetrap.js +1021 -0
  85. data/vendor/assets/javascripts/string_includes.js +14 -0
  86. data/vendor/assets/stylesheets/clusterize.css +27 -0
  87. metadata +100 -3
  88. data/app/assets/javascripts/task/sticky_element.js.coffee +0 -16
@@ -8,6 +8,9 @@ module Shipit
8
8
  MAX_READ = 64.kilobytes
9
9
 
10
10
  Error = Class.new(StandardError)
11
+ Failed = Class.new(Error)
12
+ NotFound = Class.new(Error)
13
+ Denied = Class.new(Error)
11
14
 
12
15
  attr_reader :out, :code, :chdir, :env, :args, :pid, :timeout
13
16
 
@@ -72,8 +75,14 @@ module Shipit
72
75
  child_in = @out = @pid = nil
73
76
  FileUtils.mkdir_p(@chdir)
74
77
  with_full_path do
75
- @out, child_in, @pid = PTY.spawn(@env, *interpolated_arguments, chdir: @chdir)
76
- child_in.close
78
+ begin
79
+ @out, child_in, @pid = PTY.spawn(@env, *interpolated_arguments, chdir: @chdir)
80
+ child_in.close
81
+ rescue Errno::ENOENT
82
+ raise NotFound, "#{Shellwords.split(interpolated_arguments.first).first}: command not found"
83
+ rescue Errno::EACCES
84
+ raise Denied, "#{Shellwords.split(interpolated_arguments.first).first}: Permission denied"
85
+ end
77
86
  end
78
87
  @started = true
79
88
  self
@@ -93,21 +102,16 @@ module Shipit
93
102
 
94
103
  _, status = Process.waitpid2(@pid)
95
104
  @code = status.exitstatus
96
- yield exit_message + "\n" unless success?
97
-
98
105
  self
99
106
  end
100
107
 
101
- def check_status
102
- end
103
-
104
108
  def red(text)
105
109
  "\033[1;31m#{text}\033[0m"
106
110
  end
107
111
 
108
112
  def stream!(&block)
109
113
  stream(&block)
110
- raise Command::Error.new(exit_message) unless success?
114
+ raise Failed.new(exit_message) unless success?
111
115
  self
112
116
  end
113
117
 
@@ -146,7 +150,7 @@ module Shipit
146
150
  Timeout.timeout(wait) do
147
151
  read_stream(@out, &block)
148
152
  end
149
- rescue Timeout::Error
153
+ rescue Timeout::Error, Errno::EIO # Somewhat expected on Linux: http://stackoverflow.com/a/10306782
150
154
  end
151
155
 
152
156
  def kill(sig)
data/lib/shipit/engine.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'bootstrap'
2
+
1
3
  module Shipit
2
4
  class Engine < ::Rails::Engine
3
5
  isolate_namespace Shipit
@@ -8,15 +10,21 @@ module Shipit
8
10
  Rails.application.routes.default_url_options[:host] = Shipit.host
9
11
  Shipit::Engine.routes.default_url_options[:host] = Shipit.host
10
12
 
13
+ app.config.assets.paths << Emoji.images_path
11
14
  app.config.assets.precompile += %w(
12
15
  favicon.ico
13
16
  task.js
14
17
  shipit.js
15
18
  shipit.css
19
+ shipit_bs.js
20
+ shipit_bs.css
16
21
  )
17
22
  app.config.assets.precompile << proc do |path|
18
23
  path =~ /\Aplugins\/[\-\w]+\.(js|css)\Z/
19
24
  end
25
+ app.config.assets.precompile << proc do |path|
26
+ path.start_with?('emoji/') && path.end_with?('.png')
27
+ end
20
28
 
21
29
  ActionDispatch::ExceptionWrapper.rescue_responses[Shipit::TaskDefinition::NotFound.name] = :not_found
22
30
 
@@ -0,0 +1,16 @@
1
+ module TemplateRendererExtension
2
+ private
3
+
4
+ def render_template(template, layout_name = nil, *args)
5
+ if layout_name && bootstrap?(template)
6
+ layout_name = 'layouts/shipit_bootstrap'
7
+ end
8
+ super(template, layout_name, *args)
9
+ end
10
+
11
+ def bootstrap?(template)
12
+ template.identifier.start_with?('bootstrap/') || template.identifier.start_with?("#{Shipit.bootstrap_view_path}/")
13
+ end
14
+ end
15
+
16
+ ActionView::TemplateRenderer.prepend(TemplateRendererExtension)
@@ -1,3 +1,3 @@
1
1
  module Shipit
2
- VERSION = '0.8.9'
2
+ VERSION = '0.9.0'
3
3
  end
@@ -15,11 +15,22 @@ module Shipit
15
15
  assert_response :success
16
16
  end
17
17
 
18
+ test "deploys can be observed as raw text" do
19
+ get :show, stack_id: @stack, id: @deploy.id, format: "txt"
20
+ assert_response :success
21
+ assert_equal("text/plain", @response.content_type)
22
+ end
23
+
18
24
  test ":new is success" do
19
25
  get :new, stack_id: @stack.to_param, sha: @commit.sha
20
26
  assert_response :success
21
27
  end
22
28
 
29
+ test ":new works for not yet deployed stacks" do
30
+ @stack = shipit_stacks(:undeployed_stack)
31
+ get :new, stack_id: @stack.to_param, sha: @stack.commits.last.sha
32
+ end
33
+
23
34
  test ":new shows a warning if a deploy is already running" do
24
35
  shipit_deploys(:shipit_running).update_column(:status, 'running')
25
36
 
@@ -167,5 +167,10 @@ module Shipit
167
167
  patch :update, id: @stack.to_param, stack: {ignore_ci: false}, return_to: stack_path(@stack)
168
168
  assert_redirected_to stack_path(@stack)
169
169
  end
170
+
171
+ test "#lookup redirects to the canonical URL" do
172
+ get :lookup, id: @stack.id
173
+ assert_redirected_to stack_path(@stack)
174
+ end
170
175
  end
171
176
  end
@@ -52,6 +52,12 @@ module Shipit
52
52
  assert_response :ok
53
53
  end
54
54
 
55
+ test "triggered tasks can be observed as raw text" do
56
+ get :show, stack_id: @stack, id: @task.id, format: "txt"
57
+ assert_response :success
58
+ assert_equal("text/plain", @response.content_type)
59
+ end
60
+
55
61
  test ":abort call abort! on the deploy" do
56
62
  @task = shipit_deploys(:shipit_running)
57
63
  @task.pid = 42
@@ -13,6 +13,8 @@ development:
13
13
  # api_endpoint:
14
14
  host: 'http://localhost:3000'
15
15
  redis_url: "redis://127.0.0.1:6379/7"
16
+ # features:
17
+ # - bootstrap
16
18
 
17
19
  test:
18
20
  secret_key_base: s3cr3ts3cr3ts3cr3ts3cr3ts3cr3ts3cr3t
@@ -29,3 +31,5 @@ test:
29
31
  # -
30
32
  # -
31
33
  redis_url: "redis://127.0.0.1:6379/7"
34
+ # features:
35
+ # - bootstrap
@@ -1,4 +1,6 @@
1
1
  development:
2
+ features:
3
+ - bootstrap
2
4
  secret_key_base: s3cr3ts3cr3ts3cr3ts3cr3ts3cr3ts3cr3t
3
5
  # github_domain: github.shopify.com
4
6
  github_oauth:
@@ -0,0 +1,32 @@
1
+ review:
2
+ checklist:
3
+ - Blah Blah
4
+ checks:
5
+ - echo 42
6
+
7
+ deploy:
8
+ variables:
9
+ -
10
+ name: REBUILD
11
+ title: Force artifacts rebuild
12
+ default: '0'
13
+ pre:
14
+ - echo pre
15
+ override:
16
+ - echo 1
17
+ - env
18
+ - sleep 10
19
+ post:
20
+ - echo post
21
+
22
+ rollback:
23
+ override:
24
+ - echo done
25
+
26
+
27
+ tasks:
28
+ restart:
29
+ action: Restart application
30
+ description: Trigger the restart of both app and jobs servers
31
+ steps:
32
+ - cap $ENVIRONMENT deploy:restart
@@ -1 +1,2 @@
1
1
  foo
2
+ sadsadasd
@@ -10,10 +10,15 @@ deploy:
10
10
  name: REBUILD
11
11
  title: Force artifacts rebuild
12
12
  default: '0'
13
+ pre:
14
+ - echo pre
13
15
  override:
14
16
  - echo 1
17
+ - env
15
18
  - sleep 10
16
-
19
+ post:
20
+ - echo post
21
+
17
22
  rollback:
18
23
  override:
19
24
  - echo done
Binary file
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 20160303203940) do
14
+ ActiveRecord::Schema.define(version: 20160324155046) do
15
15
 
16
16
  create_table "api_clients", force: :cascade do |t|
17
17
  t.text "permissions", limit: 65535
@@ -180,6 +180,8 @@ ActiveRecord::Schema.define(version: 20160303203940) do
180
180
  t.text "env"
181
181
  t.integer "confirmations", default: 0, null: false
182
182
  t.boolean "allow_concurrency", default: false, null: false
183
+ t.datetime "started_at"
184
+ t.datetime "ended_at"
183
185
  end
184
186
 
185
187
  add_index "tasks", ["rolled_up", "created_at", "status"], name: "index_tasks_on_rolled_up_and_created_at_and_status"
@@ -142,6 +142,8 @@ module Shipit
142
142
  chunks: create_chunks,
143
143
  additions: Faker::Number.number(3),
144
144
  deletions: Faker::Number.number(3),
145
+ started_at: Random.rand(15.minutes.to_i).seconds.ago,
146
+ ended_at: Time.now.utc,
145
147
  user: users.sample,
146
148
  )
147
149
  deploy.write("$ cap production deploy SHA=yolo")
@@ -154,6 +156,8 @@ module Shipit
154
156
  status: 'success',
155
157
  user: users.sample,
156
158
  chunks: create_chunks,
159
+ started_at: Random.rand(15.minutes.to_i).seconds.ago,
160
+ ended_at: Time.now.utc,
157
161
  )
158
162
 
159
163
  stack.tasks.create!(
@@ -167,6 +171,8 @@ module Shipit
167
171
  'steps' => ['cap $ENVIRONMENT restart'],
168
172
  ),
169
173
  chunks: create_chunks,
174
+ started_at: Random.rand(15.minutes.to_i).seconds.ago,
175
+ ended_at: Time.now.utc,
170
176
  )
171
177
  end
172
178
  end
Binary file
Binary file
@@ -19,6 +19,8 @@ shipit2:
19
19
  additions: 12
20
20
  deletions: 64
21
21
  created_at: <%= (60 - 2).minutes.ago.to_s(:db) %>
22
+ started_at: <%= (60 - 2).minutes.ago.to_s(:db) %>
23
+ ended_at: <%= (60 - 4).minutes.ago.to_s(:db) %>
22
24
 
23
25
  shipit_restart:
24
26
  user: walrus
@@ -41,6 +43,8 @@ shipit_restart:
41
43
  ]
42
44
  }
43
45
  created_at: <%= (60 - 3).minutes.ago.to_s(:db) %>
46
+ started_at: <%= (60 - 3).minutes.ago.to_s(:db) %>
47
+ ended_at: <%= (60 - 4).minutes.ago.to_s(:db) %>
44
48
 
45
49
  shipit_pending:
46
50
  since_commit_id: 2 # second
@@ -62,6 +66,7 @@ shipit_running:
62
66
  additions: 420
63
67
  deletions: 342
64
68
  created_at: <%= (60 - 5).minutes.ago.to_s(:db) %>
69
+ started_at: <%= (60 - 5).minutes.ago.to_s(:db) %>
65
70
 
66
71
  shipit_complete:
67
72
  user: bob
@@ -73,6 +78,8 @@ shipit_complete:
73
78
  additions: 420
74
79
  deletions: 342
75
80
  created_at: <%= (60 - 6).minutes.ago.to_s(:db) %>
81
+ started_at: <%= (60 - 6).minutes.ago.to_s(:db) %>
82
+ ended_at: <%= (60 - 2).minutes.ago.to_s(:db) %>
76
83
 
77
84
  shipit_aborted:
78
85
  user: bob
@@ -85,6 +92,8 @@ shipit_aborted:
85
92
  deletions: 342
86
93
  rollback_once_aborted: true
87
94
  created_at: <%= (60 - 7).minutes.ago.to_s(:db) %>
95
+ started_at: <%= (60 - 7).minutes.ago.to_s(:db) %>
96
+ ended_at: <%= (60 - 6).minutes.ago.to_s(:db) %>
88
97
 
89
98
  shipit_rollback:
90
99
  user: bob
@@ -97,3 +106,5 @@ shipit_rollback:
97
106
  additions: 420
98
107
  deletions: 342
99
108
  created_at: <%= (60 - 8).minutes.ago.to_s(:db) %>
109
+ started_at: <%= (60 - 8).minutes.ago.to_s(:db) %>
110
+ ended_at: <%= (60 - 7).minutes.ago.to_s(:db) %>
@@ -110,7 +110,7 @@ module Shipit
110
110
 
111
111
  @stack.deploys.create!(
112
112
  user_id: walrus.id,
113
- since_commit: @stack.last_deployed_commit,
113
+ since_commit: @stack.commits.first,
114
114
  until_commit: new_commit,
115
115
  status: 'success',
116
116
  )
@@ -103,6 +103,16 @@ module Shipit
103
103
  end
104
104
  end
105
105
 
106
+ test "transitioning to success persists `ended_at`" do
107
+ deploy = shipit_deploys(:shipit_running)
108
+
109
+ assert_nil deploy.ended_at
110
+ deploy.complete!
111
+ deploy.reload
112
+ assert_instance_of ActiveSupport::TimeWithZone, deploy.ended_at
113
+ assert_in_delta Time.now.utc, deploy.ended_at, 2
114
+ end
115
+
106
116
  test "transitioning to failed causes an event to be broadcasted" do
107
117
  deploy = shipit_deploys(:shipit_pending)
108
118
 
@@ -113,6 +123,16 @@ module Shipit
113
123
  end
114
124
  end
115
125
 
126
+ test "transitioning to failed persists `ended_at`" do
127
+ deploy = shipit_deploys(:shipit_running)
128
+
129
+ assert_nil deploy.ended_at
130
+ deploy.failure!
131
+ deploy.reload
132
+ assert_instance_of ActiveSupport::TimeWithZone, deploy.ended_at
133
+ assert_in_delta Time.now.utc, deploy.ended_at, 2
134
+ end
135
+
116
136
  test "transitioning to error causes an event to be broadcasted" do
117
137
  deploy = shipit_deploys(:shipit_pending)
118
138
 
@@ -123,6 +143,16 @@ module Shipit
123
143
  end
124
144
  end
125
145
 
146
+ test "transitioning to error persists `ended_at`" do
147
+ deploy = shipit_deploys(:shipit_running)
148
+
149
+ assert_nil deploy.ended_at
150
+ deploy.error!
151
+ deploy.reload
152
+ assert_instance_of ActiveSupport::TimeWithZone, deploy.ended_at
153
+ assert_in_delta Time.now.utc, deploy.ended_at, 2
154
+ end
155
+
126
156
  test "transitioning to running causes an event to be broadcasted" do
127
157
  deploy = shipit_deploys(:shipit_pending)
128
158
 
@@ -133,6 +163,16 @@ module Shipit
133
163
  end
134
164
  end
135
165
 
166
+ test "transitioning to running persists `started_at`" do
167
+ deploy = shipit_deploys(:shipit_pending)
168
+
169
+ assert_nil deploy.started_at
170
+ deploy.run!
171
+ deploy.reload
172
+ assert_instance_of ActiveSupport::TimeWithZone, deploy.started_at
173
+ assert_in_delta Time.now.utc, deploy.started_at, 2
174
+ end
175
+
136
176
  test "creating a deploy causes an event to be broadcasted" do
137
177
  shipit = shipit_stacks(:shipit)
138
178
  deploy = shipit.deploys.build(