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
@@ -0,0 +1,97 @@
1
+ <% content_for :page_title do %>
2
+ Shipit
3
+ <% end %>
4
+
5
+ <div class="jumbotron bg-warning">
6
+ <div class="container">
7
+ <h1 class="display-4">Oops! You're not ready to ship just yet.</h1>
8
+ <p class="lead">
9
+ Shipit is missing some of the information it needs to work properly.
10
+ Once you've added the configuration, make sure you restart the Rails server.
11
+ </p>
12
+ </div>
13
+ </div>
14
+
15
+ <div class="container">
16
+ <section>
17
+ <header>
18
+ <h2>GitHub application</h2>
19
+ </header>
20
+
21
+ <% if Shipit.github_oauth_id.blank? || Shipit.github_oauth_secret.blank? %>
22
+ <p><%= missing_github_oauth_message %></p>
23
+ <% end %>
24
+ <p id="github_oauth_id">
25
+ ID:
26
+ <% if Shipit.github_oauth_id.present? %>
27
+ Success!
28
+ <% else %>
29
+ <span class="missing">
30
+ <%= missing_github_oauth_id_message %>
31
+ </span>
32
+ <% end %>
33
+ </p>
34
+
35
+ <p id="github_oauth_secret">
36
+ Secret:
37
+ <% if Shipit.github_oauth_secret.present? %>
38
+ Success!
39
+ <% else %>
40
+ <span class="missing">
41
+ <%= missing_github_oauth_secret_message %>
42
+ </span>
43
+ <% end %>
44
+ </p>
45
+ </section>
46
+
47
+ <section>
48
+ <header>
49
+ <h2>GitHub API</h2>
50
+ </header>
51
+
52
+ <p id="github_api">
53
+ Token:
54
+ <% if Shipit.github_api_credentials.present? %>
55
+ Success!
56
+ <% else %>
57
+ <span class="missing">
58
+ <%= missing_github_api_credentials_message %>
59
+ </span>
60
+ <% end %>
61
+ </p>
62
+ </section>
63
+
64
+ <section>
65
+ <header>
66
+ <h2>Redis</h2>
67
+ </header>
68
+
69
+ <p id="redis_url">
70
+ Redis:
71
+ <% if Shipit.redis_url.present? %>
72
+ Success!
73
+ <% else %>
74
+ <span class="missing">
75
+ <%= missing_redis_url_message %>
76
+ </span>
77
+ <% end %>
78
+ </p>
79
+ </section>
80
+
81
+ <section>
82
+ <header>
83
+ <h2>Host</h2>
84
+ </header>
85
+
86
+ <p id="host">
87
+ Host:
88
+ <% if Shipit.host.present? %>
89
+ Success!
90
+ <% else %>
91
+ <span class="missing">
92
+ <%= missing_host_message %>
93
+ </span>
94
+ <% end %>
95
+ </p>
96
+ </section>
97
+ </div>
@@ -0,0 +1,44 @@
1
+ <% content_for :page_title do %>
2
+ Create a stack
3
+ <% end %>
4
+
5
+ <div class='container'>
6
+ <section>
7
+ <header>
8
+ <h1>Create a stack</h1>
9
+ </header>
10
+ <%= form_for @stack do |f| %>
11
+ <fieldset class='form-group'>
12
+ <%= label_tag :stack_repo_owner, 'Repo' %>
13
+ <div class='input-group'>
14
+ <div class='input-group-addon'><%= Shipit.github_url %>/</div>
15
+ <%= f.text_field :repo_owner, placeholder: 'e.g. Shopify', required: true, class: 'form-control' %>
16
+ <div class='input-group-addon'>/</div>
17
+ <%= f.text_field :repo_name, placeholder: 'e.g. shipit-engine', required: true, pattern: "^[a-zA-Z0-9\-_\.]+$", class: 'form-control' %>
18
+ </div>
19
+ </fieldset>
20
+ <fieldset class='form-group'>
21
+ <%= f.label :branch %>
22
+ <%= f.text_field :branch, placeholder: 'master', class: 'form-control' %>
23
+ </fieldset>
24
+ <fieldset class='form-group'>
25
+ <%= f.label :environment %>
26
+ <%= f.text_field :environment, placeholder: 'production', class: 'form-control' %>
27
+ </fieldset>
28
+ <fieldset class='form-group'>
29
+ <%= f.label :deploy_url %>
30
+ <%= f.text_field :deploy_url, placeholder: 'https://', class: 'form-control' %>
31
+ <small class='text-muted'>Where is this stack deployed to?</small>
32
+ </fieldset>
33
+ <fieldset class='form-group checkbox'>
34
+ <%= label_tag :stack_ignore_ci do %>
35
+ <%= f.check_box :ignore_ci, class: 'checkbox' %>
36
+ Allow deploys regardless of CI status
37
+ <% end %>
38
+ </fieldset>
39
+ <fieldset>
40
+ <%= f.submit class: 'btn btn-primary' %>
41
+ </fieldset>
42
+ <% end %>
43
+ </section>
44
+ </div>
@@ -48,7 +48,7 @@
48
48
  </div>
49
49
  </header>
50
50
 
51
- <div class="main" data-layout-content>
51
+ <div class="main <%= content_for(:main_classes) %>" data-layout-content>
52
52
  <%= yield %>
53
53
  </div>
54
54
  </body>
@@ -0,0 +1,44 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-controller="<%= controller_name %>" data-action="<%= action_name %>">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6
+ <meta http-equiv="x-ua-compatible" content="ie=edge">
7
+ <title><%= [Shipit.app_name, @stack.try!(:repo_name)].compact.join(' - ') %></title>
8
+
9
+ <%= favicon_link_tag %>
10
+ <%= stylesheet_link_tag :shipit_bs, media: 'all' %>
11
+ <%= javascript_include_tag :shipit_bs %>
12
+
13
+ <%= csrf_meta_tags %>
14
+ </head>
15
+ <body>
16
+ <% flash.each do |name, msg| %>
17
+ <%= content_tag :div, msg, class: ["flash-#{name}", :flash] %>
18
+ <% end %>
19
+
20
+ <nav class="navbar navbar-fixed-top navbar-light bg-faded">
21
+ <%= link_to "Shipit", root_path, class: "navbar-brand" %>
22
+
23
+ <ul class="nav navbar-nav">
24
+ <li class="nav-item active">
25
+ <%= link_to "#", class: "nav-link" do %>
26
+ <%= yield :page_title %>
27
+ <% end %>
28
+ </li>
29
+ </ul>
30
+
31
+ <div class="pull-xs-right">
32
+ <%= link_to "Shipit v#{Shipit::VERSION}", "https://github.com/Shopify/shipit-engine/tree/v#{Shipit::VERSION}" %>
33
+ </div>
34
+
35
+ <div class="container pull-xs-right">
36
+ <%= yield :primary_navigation %>
37
+ </div>
38
+ </nav>
39
+
40
+ <div class="main">
41
+ <%= yield %>
42
+ </div>
43
+ </body>
44
+ </html>
@@ -5,13 +5,14 @@
5
5
  <span class="commit-title"><%= render_commit_message_with_link commit %></span>
6
6
  <p class="commit-meta">
7
7
  <span class="sha"><%= render_commit_id_link(commit) %></span>
8
- <%= timeago_tag(commit.committed_at, force: true) %>
9
- <span class="utc-timecode">at <%= commit.committed_at.strftime('%H:%M:%S') %> UTC</span>
10
8
  <% if commit.additions? && commit.deletions? %>
11
9
  <span class="code-additions">+<%= commit.additions %></span>
12
10
  <span class="code-deletions">-<%= commit.deletions %></span>
13
11
  <% end %>
14
12
  </p>
13
+ <p class="commit-meta">
14
+ <%= timeago_tag(commit.committed_at, force: true) %>
15
+ </p>
15
16
  </div>
16
17
  <div class="commit-actions">
17
18
  <%= deploy_button(commit) %>
@@ -13,12 +13,21 @@
13
13
  </a>
14
14
  </span>
15
15
  <p class="commit-meta">
16
+ <%= deploy.rollback? ? 'rolled back' : 'deployed' %>
16
17
  <span class="sha"><%= link_to_github_deploy(deploy) %></span>
17
- <%= deploy.rollback? ? 'rolled back' : 'deployed' %> <%= timeago_tag(deploy.created_at, force: true) %>
18
- <span class="utc-timecode">at <%= deploy.created_at.strftime('%H:%M:%S') %> UTC</span>
19
18
  <span class="code-additions">+<%= deploy.additions %></span>
20
19
  <span class="code-deletions">-<%= deploy.deletions %></span>
21
20
  </p>
21
+ <p class="commit-meta">
22
+ <% if read_only %>
23
+ <span class="utc-timecode">on <%= deploy.created_at.strftime('%Y-%m-%d %H:%M:%S') %> UTC</span>
24
+ <% else %>
25
+ <%= timeago_tag(deploy.created_at, force: true) %>
26
+ <% end %>
27
+ <% if deploy.duration? %>
28
+ in <%= deploy.duration %>
29
+ <% end %>
30
+ </p>
22
31
  </div>
23
32
  <% unless read_only %>
24
33
  <div class="commit-actions">
@@ -5,7 +5,7 @@
5
5
  deploying
6
6
  <% end %>
7
7
  <span class="short-sha"><%= render_commit_id_link(@deploy.until_commit) %></span>
8
- <%= timeago_tag(@deploy.created_at, force: true) %> at <%= @deploy.created_at %>
8
+ <%= timeago_tag(@deploy.created_at, force: true) %>
9
9
  <% end %>
10
10
 
11
11
  <%= render partial: 'shipit/tasks/task_output', locals: {task: @deploy} %>
@@ -6,7 +6,7 @@
6
6
  <section>
7
7
  <div class="setting-section">
8
8
  <%= form_for @stack do |f| %>
9
- <p>
9
+ <div class="field-wrapper">
10
10
  <%= label_tag "Repo" %>
11
11
  <br>
12
12
  <%= Shipit.github_url %>
@@ -14,25 +14,25 @@
14
14
  <%= f.text_field :repo_owner, placeholder: 'e.g. Shopify', required: true, class: "repo" %>
15
15
  /
16
16
  <%= f.text_field :repo_name, required: true, pattern: "^[a-zA-Z0-9\-_\.]+$", class: "repo" %>
17
- </p>
18
- <p>
17
+ </div>
18
+ <div class="field-wrapper">
19
19
  <%= f.label :branch %>
20
20
  <%= f.text_field :branch, placeholder: 'master' %>
21
- </p>
22
- <p>
21
+ </div>
22
+ <div class="field-wrapper">
23
23
  <%= f.label :environment %>
24
24
  <%= f.text_field :environment, placeholder: 'production' %>
25
- </p>
26
- <p>
25
+ </div>
26
+ <div class="field-wrapper">
27
27
  <%= f.label :deploy_url %>
28
+ <span class="form-hint"><small>Where is this stack deployed to?</small></span>
28
29
  <%= f.text_field :deploy_url, placeholder: 'https://' %>
29
- <span class="form-hint">Where is this stack deployed to?</span>
30
- </p>
31
- <p>
30
+ </div>
31
+ <div class="field-wrapper">
32
32
  <%= f.check_box :ignore_ci %>
33
33
  <%= f.label :ignore_ci, "Allow deploys regardless of CI status" %>
34
- </p>
35
- <p><%= f.submit class: 'btn' %></p>
34
+ </div>
35
+ <div class="field-wrapper"><%= f.submit class: 'btn' %></div>
36
36
  <% end %>
37
37
  </div>
38
38
  </section>
@@ -8,6 +8,11 @@
8
8
 
9
9
  <div class="setting-section">
10
10
  <%= form_for @stack do |f| %>
11
+ <div class="field-wrapper">
12
+ <%= f.label :environment %>
13
+ <%= f.text_field :environment, placeholder: 'production' %>
14
+ </div>
15
+
11
16
  <div class="field-wrapper">
12
17
  <%= f.label :deploy_url, 'Deploy URL (Where is this stack deployed to?)' %>
13
18
  <%= f.text_field :deploy_url, placeholder: 'https://' %>
@@ -42,7 +42,7 @@
42
42
  Deploys are locked by <%= @stack.lock_author.name %>
43
43
  </h2>
44
44
  <p class="banner__text">
45
- <%= auto_link @stack.lock_reason %>
45
+ <%= auto_link emojify(@stack.lock_reason) %>
46
46
  </p>
47
47
  </div>
48
48
  </div>
@@ -1,3 +1,5 @@
1
+ <%- read_only ||= false -%>
2
+
1
3
  <li class="task" id="task-<%= task.id %>" data-status="<%= task.status %>">
2
4
  <%= render 'shipit/commits/commit_author', commit: task %>
3
5
  <a href="<%= stack_task_path(@stack, task) %>" class="status status--<%= task.status %>" data-tooltip="<%= task.status.capitalize %>">
@@ -12,8 +14,14 @@
12
14
  </a>
13
15
  </span>
14
16
  <p class="commit-meta">
15
- ran a command <%= timeago_tag(task.created_at, force: true) %>
16
- <span class="utc-timecode">at <%= task.created_at.strftime('%H:%M:%S') %> UTC</span>
17
+ ran a command
18
+ </p>
19
+ <p class="commit-meta">
20
+ <% if read_only %>
21
+ <span class="utc-timecode">on <%= task.created_at.strftime('%Y-%m-%d %H:%M:%S') %> UTC</span>
22
+ <% else %>
23
+ <%= timeago_tag(task.created_at, force: true) %>
24
+ <% end %>
17
25
  </p>
18
26
  </div>
19
27
  </li>
@@ -1,3 +1,5 @@
1
+ <% content_for :main_classes do %>no-footer<% end %>
2
+
1
3
  <%= javascript_include_tag 'task' %>
2
4
  <%= include_plugins(@stack) %>
3
5
  <%= render partial: 'shipit/stacks/header', locals: { stack: @stack } %>
@@ -9,6 +11,7 @@
9
11
  <div class="deploy-main" data-task="<%= {repo: @stack.github_repo_name, description: task_description(task)}.to_json %>">
10
12
  <span class="deploy-tasks"></span>
11
13
  <div class="deploy-banner" data-status="<%= task.status %>">
14
+ <div class="deploy-banner-status"></div>
12
15
  <div class="deploy-banner-section stack-link">
13
16
  <%= link_to "Return to #{@stack.repo_name}/#{@stack.environment}", stack_path(@stack) %>
14
17
  </div>
@@ -17,6 +20,7 @@
17
20
  <span class="deploy-status">
18
21
  <%= content_for :task_title %>
19
22
  </span>
23
+ <%= link_to('(view raw output)', { format: :txt }) %>
20
24
  </div>
21
25
 
22
26
  <div class="deploy-banner-section action-buttons">
@@ -34,5 +38,11 @@
34
38
  </div>
35
39
  </div>
36
40
 
37
- <pre class="nowrap" data-status="<%= task.status %>"><code data-next-chunks-url="<%= next_chunks_url(task) %>"><%= task.chunk_output %></code></pre>
41
+ <div class="search-bar hidden">
42
+ <input type="search" class="search-input" />
43
+ </div>
44
+
45
+ <div class="clusterize-scroll task-output-container">
46
+ <pre class="nowrap" data-status="<%= task.status %>"><code class="clusterize-content" data-output="<%= task.chunk_output %>" data-next-chunks-url="<%= next_chunks_url(task) %>"></code></pre>
47
+ </div>
38
48
  </div>
@@ -1,6 +1,6 @@
1
1
  <% content_for :task_title do %>
2
2
  executing <%= @task.definition.id %>
3
- <%= timeago_tag(@task.created_at, force: true) %> at <%= @task.created_at %>
3
+ <%= timeago_tag(@task.created_at, force: true) %>
4
4
  <% end %>
5
5
 
6
6
  <%= render partial: 'shipit/tasks/task_output', locals: {task: @task} %>
data/config/routes.rb CHANGED
@@ -85,4 +85,5 @@ Shipit::Engine.routes.draw do
85
85
  end
86
86
  end
87
87
  end
88
+ get '/stacks/:id' => 'stacks#lookup'
88
89
  end
@@ -0,0 +1,25 @@
1
+ class AddStartedAtAndEndedAtOnTasks < ActiveRecord::Migration
2
+ def up
3
+ add_column :tasks, :started_at, :datetime, null: true
4
+ add_column :tasks, :ended_at, :datetime, null: true
5
+
6
+ say "Migrating #{Shipit::Task.count} tasks:"
7
+ Shipit::Task.find_each.with_index do |task, index|
8
+ unless task.started_at
9
+ task.update_columns(
10
+ started_at: task.created_at,
11
+ ended_at: task.updated_at, # good enough approximation but not perfect
12
+ )
13
+ puts if index % 100 == 0
14
+ print '.'
15
+ end
16
+ end
17
+ puts
18
+ say "Done"
19
+ end
20
+
21
+ def down
22
+ remove_column :tasks, :started_at
23
+ remove_column :tasks, :ended_at
24
+ end
25
+ end
data/lib/shipit.rb CHANGED
@@ -10,9 +10,11 @@ require 'sass-rails'
10
10
  require 'coffee-rails'
11
11
  require 'jquery-rails'
12
12
  require 'rails-timeago'
13
+ require 'lodash-rails'
13
14
  require 'ansi_stream'
14
15
  require 'autoprefixer-rails'
15
16
  require 'rails_autolink'
17
+ require 'gemoji'
16
18
 
17
19
  require 'omniauth-github'
18
20
 
@@ -27,6 +29,9 @@ require 'octokit'
27
29
  require 'faraday-http-cache'
28
30
 
29
31
  require 'shipit/version'
32
+
33
+ require 'shipit/template_renderer_extension'
34
+
30
35
  require 'shipit/paginator'
31
36
  require 'shipit/null_serializer'
32
37
  require 'shipit/csv_serializer'
@@ -171,6 +176,14 @@ module Shipit
171
176
  end
172
177
  end
173
178
 
179
+ def feature_bootstrap?
180
+ secrets.features.try!(:include?, 'bootstrap')
181
+ end
182
+
183
+ def bootstrap_view_path
184
+ @bootstrap_view_path ||= Engine.root.join('app/views/bootstrap')
185
+ end
186
+
174
187
  protected
175
188
 
176
189
  def revision_file