shipit-engine 0.8.9 → 0.9.0

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 (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(