shipit-engine 0.5.2 → 0.6.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 (274) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/shipit/api/cacheable.rb +13 -0
  3. data/app/controllers/concerns/shipit/api/paginable.rb +37 -0
  4. data/app/controllers/concerns/shipit/api/rendering.rb +25 -0
  5. data/app/controllers/concerns/{api/paginable.rb → shipit/pagination.rb} +5 -13
  6. data/app/controllers/shipit/api/base_controller.rb +68 -0
  7. data/app/controllers/shipit/api/deploys_controller.rb +17 -0
  8. data/app/controllers/shipit/api/hooks_controller.rb +53 -0
  9. data/app/controllers/shipit/api/locks_controller.rb +32 -0
  10. data/app/controllers/shipit/api/outputs_controller.rb +17 -0
  11. data/app/controllers/shipit/api/stacks_controller.rb +21 -0
  12. data/app/controllers/shipit/api/tasks_controller.rb +20 -0
  13. data/app/controllers/shipit/commit_checks_controller.rb +26 -0
  14. data/app/controllers/shipit/deploys_controller.rb +47 -0
  15. data/app/controllers/shipit/github_authentication_controller.rb +27 -0
  16. data/app/controllers/shipit/rollbacks_controller.rb +26 -0
  17. data/app/controllers/shipit/shipit_controller.rb +62 -0
  18. data/app/controllers/shipit/stacks_controller.rb +81 -0
  19. data/app/controllers/shipit/status_controller.rb +7 -0
  20. data/app/controllers/shipit/tasks_controller.rb +48 -0
  21. data/app/controllers/shipit/webhooks_controller.rb +101 -0
  22. data/app/helpers/shipit/chunks_helper.rb +8 -0
  23. data/app/helpers/shipit/deploys_helper.rb +28 -0
  24. data/app/helpers/shipit/github_url_helper.rb +48 -0
  25. data/app/helpers/shipit/shipit_helper.rb +64 -0
  26. data/app/helpers/shipit/stacks_helper.rb +78 -0
  27. data/app/helpers/shipit/tasks_helper.rb +11 -0
  28. data/app/jobs/shipit/background_job.rb +24 -0
  29. data/app/jobs/shipit/background_job/unique.rb +28 -0
  30. data/app/jobs/shipit/cache_deploy_spec_job.rb +12 -0
  31. data/app/jobs/shipit/chunk_rollup_job.rb +21 -0
  32. data/app/jobs/shipit/clear_git_cache_job.rb +9 -0
  33. data/app/jobs/shipit/deliver_hook_job.rb +9 -0
  34. data/app/jobs/shipit/destroy_stack_job.rb +9 -0
  35. data/app/jobs/shipit/emit_event_job.rb +10 -0
  36. data/app/jobs/shipit/fetch_commit_stats_job.rb +9 -0
  37. data/app/jobs/shipit/fetch_deployed_revision_job.rb +23 -0
  38. data/app/jobs/shipit/git_mirror_update_job.rb +12 -0
  39. data/app/jobs/shipit/github_sync_job.rb +55 -0
  40. data/app/jobs/shipit/perform_commit_checks_job.rb +7 -0
  41. data/app/jobs/shipit/perform_task_job.rb +57 -0
  42. data/app/jobs/shipit/refresh_github_user_job.rb +9 -0
  43. data/app/jobs/shipit/refresh_statuses_job.rb +14 -0
  44. data/app/jobs/shipit/setup_github_hook_job.rb +11 -0
  45. data/app/models/shipit/anonymous_user.rb +43 -0
  46. data/app/models/shipit/api_client.rb +44 -0
  47. data/app/models/shipit/commit.rb +209 -0
  48. data/app/models/shipit/commit_checks.rb +90 -0
  49. data/app/models/shipit/delivery.rb +47 -0
  50. data/app/models/shipit/deploy.rb +153 -0
  51. data/app/models/shipit/deploy_spec.rb +150 -0
  52. data/app/models/shipit/deploy_spec/bundler_discovery.rb +61 -0
  53. data/app/models/shipit/deploy_spec/capistrano_discovery.rb +29 -0
  54. data/app/models/shipit/deploy_spec/file_system.rb +64 -0
  55. data/app/models/shipit/deploy_spec/pypi_discovery.rb +34 -0
  56. data/app/models/shipit/deploy_spec/rubygems_discovery.rb +34 -0
  57. data/app/models/shipit/github_hook.rb +148 -0
  58. data/app/models/shipit/hook.rb +86 -0
  59. data/app/models/shipit/membership.rb +8 -0
  60. data/app/models/shipit/missing_status.rb +21 -0
  61. data/app/models/shipit/output_chunk.rb +11 -0
  62. data/app/models/shipit/rollback.rb +31 -0
  63. data/app/models/shipit/stack.rb +308 -0
  64. data/app/models/shipit/status.rb +44 -0
  65. data/app/models/shipit/status_group.rb +35 -0
  66. data/app/models/shipit/task.rb +201 -0
  67. data/app/models/shipit/task_definition.rb +38 -0
  68. data/app/models/shipit/team.rb +69 -0
  69. data/app/models/shipit/unknown_status.rb +43 -0
  70. data/app/models/shipit/user.rb +83 -0
  71. data/app/models/shipit/variable_definition.rb +21 -0
  72. data/app/serializers/concerns/shipit/conditional_attributes.rb +22 -0
  73. data/app/serializers/shipit/anonymous_user_serializer.rb +4 -0
  74. data/app/serializers/shipit/commit_serializer.rb +8 -0
  75. data/app/serializers/shipit/deploy_serializer.rb +15 -0
  76. data/app/serializers/shipit/hook_serializer.rb +12 -0
  77. data/app/serializers/shipit/rollback_serializer.rb +7 -0
  78. data/app/serializers/shipit/short_commit_serializer.rb +9 -0
  79. data/app/serializers/shipit/stack_serializer.rb +33 -0
  80. data/app/serializers/shipit/tail_task_serializer.rb +39 -0
  81. data/app/serializers/shipit/task_serializer.rb +30 -0
  82. data/app/serializers/shipit/user_serializer.rb +5 -0
  83. data/app/views/{commits → shipit/commits}/_commit.html.erb +1 -1
  84. data/app/views/{commits → shipit/commits}/_commit_author.html.erb +0 -0
  85. data/app/views/{deploys → shipit/deploys}/_checklist.html.erb +0 -0
  86. data/app/views/{deploys → shipit/deploys}/_checks.html.erb +0 -0
  87. data/app/views/{deploys → shipit/deploys}/_concurrent_deploy_warning.html.erb +0 -0
  88. data/app/views/{deploys → shipit/deploys}/_deploy.html.erb +1 -1
  89. data/app/views/{deploys → shipit/deploys}/_monitoring.html.erb +0 -0
  90. data/app/views/{deploys → shipit/deploys}/_summary.html.erb +0 -0
  91. data/app/views/{deploys → shipit/deploys}/new.html.erb +3 -3
  92. data/app/views/{deploys → shipit/deploys}/rollback.html.erb +2 -2
  93. data/app/views/{deploys → shipit/deploys}/show.html.erb +1 -1
  94. data/app/views/{github_authentication → shipit/github_authentication}/failed.html.erb +0 -0
  95. data/app/views/{stacks → shipit/stacks}/_header.html.erb +0 -0
  96. data/app/views/{stacks → shipit/stacks}/index.html.erb +0 -0
  97. data/app/views/{stacks → shipit/stacks}/new.html.erb +0 -0
  98. data/app/views/{stacks → shipit/stacks}/settings.html.erb +1 -1
  99. data/app/views/{stacks → shipit/stacks}/show.html.erb +2 -2
  100. data/app/views/{statuses → shipit/statuses}/_group.html.erb +1 -1
  101. data/app/views/{statuses → shipit/statuses}/_status.html.erb +0 -0
  102. data/app/views/{tasks → shipit/tasks}/_task.html.erb +1 -1
  103. data/app/views/{tasks → shipit/tasks}/_task_output.html.erb +1 -1
  104. data/app/views/{tasks → shipit/tasks}/index.html.erb +1 -1
  105. data/app/views/{tasks → shipit/tasks}/new.html.erb +1 -1
  106. data/app/views/{tasks → shipit/tasks}/show.html.erb +1 -1
  107. data/db/migrate/20160104151742_increase_tasks_type_size_back.rb +5 -0
  108. data/db/migrate/20160104151833_convert_sti_columns.rb +10 -0
  109. data/lib/shipit.rb +11 -10
  110. data/lib/shipit/command.rb +171 -0
  111. data/lib/shipit/commands.rb +25 -0
  112. data/lib/shipit/deploy_commands.rb +21 -0
  113. data/lib/shipit/engine.rb +3 -0
  114. data/lib/shipit/rollback_commands.rb +7 -0
  115. data/lib/shipit/stack_commands.rb +60 -0
  116. data/lib/shipit/task_commands.rb +68 -0
  117. data/lib/shipit/version.rb +1 -1
  118. data/lib/tasks/cron.rake +3 -3
  119. data/test/controllers/api/base_controller_test.rb +18 -14
  120. data/test/controllers/api/deploys_controller_test.rb +56 -52
  121. data/test/controllers/api/hooks_controller_test.rb +62 -58
  122. data/test/controllers/api/locks_controller_test.rb +38 -34
  123. data/test/controllers/api/outputs_controller_test.rb +15 -11
  124. data/test/controllers/api/stacks_controller_test.rb +56 -52
  125. data/test/controllers/api/tasks_controller_test.rb +30 -26
  126. data/test/controllers/commit_checks_controller_test.rb +29 -27
  127. data/test/controllers/deploys_controller_test.rb +68 -66
  128. data/test/controllers/github_authentication_controller_test.rb +9 -7
  129. data/test/controllers/rollbacks_controller_test.rb +43 -41
  130. data/test/controllers/stacks_controller_test.rb +131 -128
  131. data/test/controllers/status_controller_test.rb +8 -6
  132. data/test/controllers/tasks_controller_test.rb +70 -68
  133. data/test/controllers/webhooks_controller_test.rb +127 -125
  134. data/test/dummy/db/development.sqlite3 +0 -0
  135. data/test/dummy/db/schema.rb +2 -2
  136. data/test/dummy/db/seeds.rb +133 -131
  137. data/test/dummy/db/test.sqlite3 +0 -0
  138. data/test/fixtures/{api_clients.yml → shipit/api_clients.yml} +0 -0
  139. data/test/fixtures/{commits.yml → shipit/commits.yml} +0 -0
  140. data/test/fixtures/{deliveries.yml → shipit/deliveries.yml} +0 -0
  141. data/test/fixtures/{github_hooks.yml → shipit/github_hooks.yml} +4 -4
  142. data/test/fixtures/{hooks.yml → shipit/hooks.yml} +0 -0
  143. data/test/fixtures/{memberships.yml → shipit/memberships.yml} +0 -0
  144. data/test/fixtures/{output_chunks.yml → shipit/output_chunks.yml} +0 -0
  145. data/test/fixtures/{stacks.yml → shipit/stacks.yml} +0 -0
  146. data/test/fixtures/{statuses.yml → shipit/statuses.yml} +0 -0
  147. data/test/fixtures/{tasks.yml → shipit/tasks.yml} +8 -8
  148. data/test/fixtures/{teams.yml → shipit/teams.yml} +0 -0
  149. data/test/fixtures/{users.yml → shipit/users.yml} +0 -0
  150. data/test/helpers/api_helper.rb +1 -1
  151. data/test/helpers/fixture_aliases_helper.rb +4 -4
  152. data/test/jobs/cache_deploy_spec_job_test.rb +15 -13
  153. data/test/jobs/chunk_rollup_job_test.rb +30 -28
  154. data/test/jobs/deliver_hook_job_test.rb +11 -9
  155. data/test/jobs/destroy_stack_job_test.rb +11 -9
  156. data/test/jobs/emit_event_job_test.rb +10 -8
  157. data/test/jobs/fetch_commit_stats_job_test.rb +10 -8
  158. data/test/jobs/fetch_deployed_revision_job_test.rb +24 -22
  159. data/test/jobs/github_sync_job_test.rb +51 -49
  160. data/test/jobs/perform_task_job_test.rb +78 -76
  161. data/test/jobs/refresh_github_user_job_test.rb +10 -8
  162. data/test/jobs/refresh_status_job_test.rb +14 -12
  163. data/test/jobs/unique_job_test.rb +18 -15
  164. data/test/models/api_client_test.rb +20 -18
  165. data/test/models/commit_checks_test.rb +63 -61
  166. data/test/models/commits_test.rb +317 -314
  167. data/test/models/delivery_test.rb +29 -27
  168. data/test/models/deploys_test.rb +289 -287
  169. data/test/models/github_hook_test.rb +45 -43
  170. data/test/models/hook_test.rb +44 -42
  171. data/test/models/membership_test.rb +9 -7
  172. data/test/models/missing_status_test.rb +16 -14
  173. data/test/models/output_chunk_test.rb +14 -12
  174. data/test/models/rollbacks_test.rb +14 -12
  175. data/test/models/stacks_test.rb +272 -270
  176. data/test/models/status_group_test.rb +18 -16
  177. data/test/models/status_test.rb +42 -40
  178. data/test/models/task_definitions_test.rb +27 -25
  179. data/test/models/team_test.rb +39 -37
  180. data/test/models/users_test.rb +61 -59
  181. data/test/unit/command_test.rb +43 -41
  182. data/test/unit/commands_test.rb +8 -6
  183. data/test/unit/csv_serializer_test.rb +28 -26
  184. data/test/unit/deploy_commands_test.rb +179 -176
  185. data/test/unit/deploy_spec_test.rb +237 -235
  186. data/test/unit/github_url_helper_test.rb +19 -17
  187. data/test/unit/shipit_test.rb +44 -42
  188. metadata +139 -137
  189. data/app/controllers/api/base_controller.rb +0 -66
  190. data/app/controllers/api/deploys_controller.rb +0 -15
  191. data/app/controllers/api/hooks_controller.rb +0 -51
  192. data/app/controllers/api/locks_controller.rb +0 -30
  193. data/app/controllers/api/outputs_controller.rb +0 -15
  194. data/app/controllers/api/stacks_controller.rb +0 -19
  195. data/app/controllers/api/tasks_controller.rb +0 -18
  196. data/app/controllers/commit_checks_controller.rb +0 -24
  197. data/app/controllers/concerns/api/cacheable.rb +0 -11
  198. data/app/controllers/concerns/api/rendering.rb +0 -23
  199. data/app/controllers/concerns/pagination.rb +0 -25
  200. data/app/controllers/deploys_controller.rb +0 -45
  201. data/app/controllers/github_authentication_controller.rb +0 -25
  202. data/app/controllers/rollbacks_controller.rb +0 -24
  203. data/app/controllers/shipit_controller.rb +0 -54
  204. data/app/controllers/stacks_controller.rb +0 -79
  205. data/app/controllers/status_controller.rb +0 -5
  206. data/app/controllers/tasks_controller.rb +0 -46
  207. data/app/controllers/webhooks_controller.rb +0 -99
  208. data/app/helpers/chunks_helper.rb +0 -6
  209. data/app/helpers/deploys_helper.rb +0 -26
  210. data/app/helpers/github_url_helper.rb +0 -46
  211. data/app/helpers/shipit_helper.rb +0 -62
  212. data/app/helpers/stacks_helper.rb +0 -76
  213. data/app/helpers/tasks_helper.rb +0 -9
  214. data/app/jobs/background_job.rb +0 -22
  215. data/app/jobs/background_job/unique.rb +0 -26
  216. data/app/jobs/cache_deploy_spec_job.rb +0 -10
  217. data/app/jobs/chunk_rollup_job.rb +0 -19
  218. data/app/jobs/clear_git_cache_job.rb +0 -7
  219. data/app/jobs/deliver_hook_job.rb +0 -7
  220. data/app/jobs/destroy_stack_job.rb +0 -7
  221. data/app/jobs/emit_event_job.rb +0 -8
  222. data/app/jobs/fetch_commit_stats_job.rb +0 -7
  223. data/app/jobs/fetch_deployed_revision_job.rb +0 -21
  224. data/app/jobs/git_mirror_update_job.rb +0 -10
  225. data/app/jobs/github_sync_job.rb +0 -53
  226. data/app/jobs/perform_commit_checks_job.rb +0 -5
  227. data/app/jobs/perform_task_job.rb +0 -55
  228. data/app/jobs/refresh_github_user_job.rb +0 -7
  229. data/app/jobs/refresh_statuses_job.rb +0 -12
  230. data/app/jobs/setup_github_hook_job.rb +0 -9
  231. data/app/models/anonymous_user.rb +0 -41
  232. data/app/models/api_client.rb +0 -42
  233. data/app/models/commit.rb +0 -207
  234. data/app/models/commit_checks.rb +0 -88
  235. data/app/models/delivery.rb +0 -45
  236. data/app/models/deploy.rb +0 -151
  237. data/app/models/deploy_spec.rb +0 -148
  238. data/app/models/deploy_spec/bundler_discovery.rb +0 -59
  239. data/app/models/deploy_spec/capistrano_discovery.rb +0 -27
  240. data/app/models/deploy_spec/file_system.rb +0 -62
  241. data/app/models/deploy_spec/pypi_discovery.rb +0 -32
  242. data/app/models/deploy_spec/rubygems_discovery.rb +0 -32
  243. data/app/models/github_hook.rb +0 -144
  244. data/app/models/hook.rb +0 -84
  245. data/app/models/membership.rb +0 -6
  246. data/app/models/missing_status.rb +0 -18
  247. data/app/models/output_chunk.rb +0 -9
  248. data/app/models/rollback.rb +0 -29
  249. data/app/models/stack.rb +0 -306
  250. data/app/models/status.rb +0 -42
  251. data/app/models/status_group.rb +0 -33
  252. data/app/models/task.rb +0 -197
  253. data/app/models/task_definition.rb +0 -36
  254. data/app/models/team.rb +0 -67
  255. data/app/models/unknown_status.rb +0 -41
  256. data/app/models/user.rb +0 -81
  257. data/app/models/variable_definition.rb +0 -19
  258. data/app/serializers/anonymous_user_serializer.rb +0 -2
  259. data/app/serializers/commit_serializer.rb +0 -6
  260. data/app/serializers/concerns/conditional_attributes.rb +0 -20
  261. data/app/serializers/deploy_serializer.rb +0 -13
  262. data/app/serializers/hook_serializer.rb +0 -10
  263. data/app/serializers/rollback_serializer.rb +0 -5
  264. data/app/serializers/short_commit_serializer.rb +0 -7
  265. data/app/serializers/stack_serializer.rb +0 -31
  266. data/app/serializers/tail_task_serializer.rb +0 -37
  267. data/app/serializers/task_serializer.rb +0 -28
  268. data/app/serializers/user_serializer.rb +0 -3
  269. data/lib/command.rb +0 -169
  270. data/lib/commands.rb +0 -23
  271. data/lib/deploy_commands.rb +0 -19
  272. data/lib/rollback_commands.rb +0 -5
  273. data/lib/stack_commands.rb +0 -58
  274. data/lib/task_commands.rb +0 -66
@@ -0,0 +1,153 @@
1
+ require 'fileutils'
2
+
3
+ module Shipit
4
+ class Deploy < Task
5
+ CONFIRMATIONS_REQUIRED = 5
6
+
7
+ state_machine :status do
8
+ after_transition to: :success, do: :schedule_continuous_delivery
9
+ after_transition to: :success, do: :update_undeployed_commits_count
10
+ after_transition to: :aborted, do: :trigger_revert_if_required
11
+ end
12
+
13
+ before_create :denormalize_commit_stats
14
+ after_commit :broadcast_update
15
+
16
+ delegate :broadcast_update, to: :stack
17
+
18
+ def build_rollback(user = nil, env: nil)
19
+ Rollback.new(
20
+ user_id: user.try!(:id),
21
+ stack_id: stack_id,
22
+ parent_id: id,
23
+ since_commit: stack.last_deployed_commit,
24
+ until_commit: until_commit,
25
+ env: env || {},
26
+ )
27
+ end
28
+
29
+ # Rolls the stack back to this deploy
30
+ def trigger_rollback(user = AnonymousUser.new, env: nil)
31
+ rollback = build_rollback(user, env: env)
32
+ rollback.save!
33
+ rollback.enqueue
34
+
35
+ lock_reason = "A rollback for #{rollback.since_commit.sha} has been triggered. " \
36
+ "Please make sure the reason for the rollback has been addressed before deploying again."
37
+ stack.update!(lock_reason: lock_reason, lock_author_id: user.id)
38
+
39
+ rollback
40
+ end
41
+
42
+ # Rolls the stack back to the **previous** deploy
43
+ def trigger_revert
44
+ rollback = Rollback.create!(
45
+ user_id: user_id,
46
+ stack_id: stack_id,
47
+ parent_id: id,
48
+ since_commit: until_commit,
49
+ until_commit: since_commit,
50
+ )
51
+ rollback.enqueue
52
+ lock_reason = "A rollback for #{until_commit.sha} has been triggered. " \
53
+ "Please make sure the reason for the rollback has been addressed before deploying again."
54
+ stack.update!(lock_reason: lock_reason, lock_author_id: user_id)
55
+ rollback
56
+ end
57
+
58
+ def rollback?
59
+ false
60
+ end
61
+
62
+ def commit_range
63
+ [since_commit, until_commit]
64
+ end
65
+
66
+ delegate :supports_rollback?, to: :stack
67
+
68
+ def rollbackable?
69
+ success? && supports_rollback? && !currently_deployed?
70
+ end
71
+
72
+ def currently_deployed?
73
+ until_commit_id == stack.last_deployed_commit.try!(:id)
74
+ end
75
+
76
+ def commits
77
+ return Commit.none unless stack
78
+
79
+ @commits ||= stack.commits.reachable.newer_than(since_commit_id).until(until_commit_id).order(id: :desc)
80
+ end
81
+
82
+ def commits_since
83
+ return Commit.none unless stack
84
+
85
+ @commits_since ||= stack.commits.reachable.newer_than(until_commit_id).order(id: :desc)
86
+ end
87
+
88
+ def since_commit_id
89
+ super || default_since_commit_id
90
+ end
91
+
92
+ def variables
93
+ stack.deploy_variables
94
+ end
95
+
96
+ def reject!
97
+ return if failed?
98
+ transaction do
99
+ flap! unless flapping?
100
+ update!(confirmations: [confirmations - 1, -1].min)
101
+ failure! if confirmed?
102
+ end
103
+ end
104
+
105
+ def accept!
106
+ return if success?
107
+ transaction do
108
+ flap! unless flapping?
109
+ update!(confirmations: [confirmations + 1, 1].max)
110
+ complete! if confirmed?
111
+ end
112
+ end
113
+
114
+ def confirmed?
115
+ confirmations.abs >= CONFIRMATIONS_REQUIRED
116
+ end
117
+
118
+ private
119
+
120
+ def trigger_revert_if_required
121
+ return unless rollback_once_aborted?
122
+ return unless supports_rollback?
123
+ trigger_revert
124
+ end
125
+
126
+ def default_since_commit_id
127
+ return unless stack
128
+ @default_since_commit_id ||= last_successful_deploy.try!(:until_commit_id)
129
+ end
130
+
131
+ def denormalize_commit_stats
132
+ self.additions = commits.map(&:additions).compact.sum
133
+ self.deletions = commits.map(&:deletions).compact.sum
134
+ end
135
+
136
+ def schedule_continuous_delivery
137
+ return unless stack.continuous_deployment?
138
+
139
+ to_deploy = stack.commits.order(:id).newer_than(until_commit).successful.last
140
+ return unless to_deploy
141
+
142
+ stack.trigger_deploy(to_deploy, to_deploy.committer)
143
+ end
144
+
145
+ def last_successful_deploy
146
+ stack.deploys.where(status: "success").last
147
+ end
148
+
149
+ def update_undeployed_commits_count
150
+ stack.update_undeployed_commits_count(until_commit)
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,150 @@
1
+ require 'pathname'
2
+
3
+ module Shipit
4
+ class DeploySpec
5
+ Error = Class.new(StandardError)
6
+
7
+ class << self
8
+ def load(json)
9
+ config = json.blank? ? {} : JSON.parse(json)
10
+ new(config)
11
+ end
12
+
13
+ def dump(spec)
14
+ JSON.dump(spec.cacheable.config) if spec
15
+ end
16
+
17
+ def bundle_path
18
+ Rails.root.join('data/bundler')
19
+ end
20
+ end
21
+
22
+ def initialize(config)
23
+ @config = config
24
+ end
25
+
26
+ delegate :bundle_path, to: :class
27
+
28
+ def cacheable
29
+ self
30
+ end
31
+
32
+ def config(*keys)
33
+ keys.flatten.reduce(@config) { |h, k| h[k] if h.respond_to?(:[]) }
34
+ end
35
+
36
+ def supports_fetch_deployed_revision?
37
+ fetch_deployed_revision_steps.present?
38
+ end
39
+
40
+ def supports_rollback?
41
+ rollback_steps.present?
42
+ end
43
+
44
+ def machine_env
45
+ config('machine', 'environment') || {}
46
+ end
47
+
48
+ def directory
49
+ config('machine', 'directory')
50
+ end
51
+
52
+ def dependencies_steps
53
+ config('dependencies', 'override') || discover_dependencies_steps || []
54
+ end
55
+ alias_method :dependencies_steps!, :dependencies_steps
56
+
57
+ def deploy_steps
58
+ config('deploy', 'override') || discover_deploy_steps
59
+ end
60
+
61
+ def deploy_steps!
62
+ deploy_steps || cant_detect!(:deploy)
63
+ end
64
+
65
+ def deploy_variables
66
+ Array.wrap(config('deploy', 'variables')).map(&VariableDefinition.method(:new))
67
+ end
68
+
69
+ def rollback_steps
70
+ config('rollback', 'override') || discover_rollback_steps
71
+ end
72
+
73
+ def rollback_steps!
74
+ rollback_steps || cant_detect!(:rollback)
75
+ end
76
+
77
+ def fetch_deployed_revision_steps
78
+ config('fetch') || discover_fetch_deployed_revision_steps
79
+ end
80
+
81
+ def fetch_deployed_revision_steps!
82
+ fetch_deployed_revision_steps || cant_detect!(:fetch)
83
+ end
84
+
85
+ def task_definitions
86
+ (config('tasks') || {}).map { |name, definition| TaskDefinition.new(name, coerce_task_definition(definition)) }
87
+ end
88
+
89
+ def find_task_definition(id)
90
+ TaskDefinition.new(id, coerce_task_definition(config('tasks', id)) || task_not_found!(id))
91
+ end
92
+
93
+ def review_checklist
94
+ (config('review', 'checklist') || discover_review_checklist || []).map(&:strip).select(&:present?)
95
+ end
96
+
97
+ def review_monitoring
98
+ (config('review', 'monitoring') || []).select(&:present?)
99
+ end
100
+
101
+ def hidden_statuses
102
+ Array.wrap(config('ci', 'hide'))
103
+ end
104
+
105
+ def required_statuses
106
+ Array.wrap(config('ci', 'require'))
107
+ end
108
+
109
+ def soft_failing_statuses
110
+ Array.wrap(config('ci', 'allow_failures'))
111
+ end
112
+
113
+ def review_checks
114
+ config('review', 'checks') || []
115
+ end
116
+
117
+ def plugins
118
+ config('plugins') || {}
119
+ end
120
+
121
+ private
122
+
123
+ def coerce_task_definition(config)
124
+ config
125
+ end
126
+
127
+ def discover_review_checklist
128
+ end
129
+
130
+ def discover_dependencies_steps
131
+ end
132
+
133
+ def discover_deploy_steps
134
+ end
135
+
136
+ def discover_rollback_steps
137
+ end
138
+
139
+ def discover_fetch_deployed_revision_steps
140
+ end
141
+
142
+ def task_not_found!(id)
143
+ raise TaskDefinition::NotFound.new("No definition for task #{id.inspect}")
144
+ end
145
+
146
+ def cant_detect!(type)
147
+ raise DeploySpec::Error.new(I18n.t("deploy_spec.hint.#{type}"))
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,61 @@
1
+ module Shipit
2
+ class DeploySpec
3
+ module BundlerDiscovery
4
+ DEFAULT_BUNDLER_WITHOUT = %w(default production development test staging benchmark debug)
5
+
6
+ def discover_dependencies_steps
7
+ discover_bundler || super
8
+ end
9
+
10
+ def discover_bundler
11
+ bundle_install if bundler?
12
+ end
13
+
14
+ def bundle_exec(command)
15
+ return command unless bundler?
16
+ "bundle exec #{command}"
17
+ end
18
+
19
+ def bundle_install
20
+ bundle = %(bundle check --path=#{bundle_path} || bundle install #{frozen_flag} --path=#{bundle_path} --retry=2)
21
+ bundle += " --without=#{bundler_without.join(':')}" unless bundler_without.empty?
22
+ [remove_ruby_version_from_gemfile, bundle]
23
+ end
24
+
25
+ def remove_ruby_version_from_gemfile
26
+ # Heroku apps often specify a ruby version.
27
+ if /darwin/ =~ RUBY_PLATFORM
28
+ # OSX is nitpicky about the -i.
29
+ %q(sed -i '' '/^ruby\s/d' Gemfile)
30
+ else
31
+ %q(sed -i '/^ruby\s/d' Gemfile)
32
+ end
33
+ end
34
+
35
+ def frozen_flag
36
+ return unless gemfile_lock_exists?
37
+ return if config('dependencies', 'bundler', 'frozen') == false
38
+ '--frozen'
39
+ end
40
+
41
+ def bundler_without
42
+ config('dependencies', 'bundler', 'without') || (gem? ? [] : DEFAULT_BUNDLER_WITHOUT)
43
+ end
44
+
45
+ def bundler?
46
+ file('Gemfile').exist?
47
+ end
48
+
49
+ def gemfile_lock_exists?
50
+ file('Gemfile.lock').exist?
51
+ end
52
+
53
+ def coerce_task_definition(config)
54
+ return super unless bundler?
55
+ config['steps'] ||= []
56
+ config['steps'] = config['steps'].map(&method(:bundle_exec))
57
+ config
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,29 @@
1
+ module Shipit
2
+ class DeploySpec
3
+ module CapistranoDiscovery
4
+ def discover_deploy_steps
5
+ discover_capistrano || super
6
+ end
7
+
8
+ def discover_rollback_steps
9
+ discover_capistrano_rollback || super
10
+ end
11
+
12
+ def discover_capistrano
13
+ [cap('deploy')] if capistrano?
14
+ end
15
+
16
+ def discover_capistrano_rollback
17
+ [cap('deploy:rollback')] if capistrano?
18
+ end
19
+
20
+ def cap(command)
21
+ bundle_exec("cap $ENVIRONMENT #{command}")
22
+ end
23
+
24
+ def capistrano?
25
+ file('Capfile').exist?
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,64 @@
1
+ module Shipit
2
+ class DeploySpec
3
+ class FileSystem < DeploySpec
4
+ include PypiDiscovery
5
+ include RubygemsDiscovery
6
+ include CapistranoDiscovery
7
+ include BundlerDiscovery
8
+
9
+ def initialize(app_dir, env)
10
+ @app_dir = Pathname(app_dir)
11
+ @env = env
12
+ end
13
+
14
+ def cacheable
15
+ DeploySpec.new(cacheable_config)
16
+ end
17
+
18
+ private
19
+
20
+ def cacheable_config
21
+ (config || {}).deep_merge(
22
+ 'ci' => {
23
+ 'hide' => hidden_statuses,
24
+ 'allow_failures' => soft_failing_statuses,
25
+ 'require' => required_statuses,
26
+ },
27
+ 'machine' => {'environment' => machine_env, 'directory' => directory},
28
+ 'review' => {
29
+ 'checklist' => review_checklist,
30
+ 'monitoring' => review_monitoring,
31
+ 'checks' => review_checks,
32
+ },
33
+ 'plugins' => plugins,
34
+ 'dependencies' => {'override' => dependencies_steps},
35
+ 'deploy' => {'override' => deploy_steps, 'variables' => deploy_variables.map(&:to_h)},
36
+ 'rollback' => {'override' => rollback_steps},
37
+ 'fetch' => fetch_deployed_revision_steps,
38
+ 'tasks' => cacheable_tasks,
39
+ )
40
+ end
41
+
42
+ def cacheable_tasks
43
+ (config('tasks') || {}).map { |k, c| [k, coerce_task_definition(c)] }.to_h
44
+ end
45
+
46
+ def config(*)
47
+ @config ||= load_config
48
+ super
49
+ end
50
+
51
+ def load_config
52
+ read_config(file("shipit.#{@env}.yml")) || read_config(file('shipit.yml'))
53
+ end
54
+
55
+ def read_config(path)
56
+ SafeYAML.load(path.read) if path.exist?
57
+ end
58
+
59
+ def file(path)
60
+ @app_dir.join(path)
61
+ end
62
+ end
63
+ end
64
+ end