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,171 @@
1
+ require 'pty'
2
+ require 'shellwords'
3
+ require 'fileutils'
4
+ require 'timeout'
5
+
6
+ module Shipit
7
+ class Command
8
+ MAX_READ = 64.kilobytes
9
+
10
+ Error = Class.new(StandardError)
11
+
12
+ attr_reader :out, :code, :chdir, :env, :args, :pid, :timeout
13
+
14
+ def initialize(*args, default_timeout: 5.minutes.to_i, env: {}, chdir:)
15
+ @args, options = parse_arguments(args)
16
+ @timeout = options['timeout'.freeze] || options[:timeout] || default_timeout
17
+ @env = env
18
+ @chdir = chdir.to_s
19
+ end
20
+
21
+ def to_s
22
+ @args.join(' ')
23
+ end
24
+
25
+ def interpolate_environment_variables(argument)
26
+ return argument.map { |a| interpolate_environment_variables(a) } if argument.is_a?(Array)
27
+
28
+ argument.gsub(/(\$\w+)/) do |variable|
29
+ variable.sub!('$', '')
30
+ Shellwords.escape(@env.fetch(variable) { ENV[variable] })
31
+ end
32
+ end
33
+
34
+ def success?
35
+ code == 0
36
+ end
37
+
38
+ def exit_message
39
+ "#{self} exited with status #{@code}"
40
+ end
41
+
42
+ def run
43
+ output = []
44
+ stream do |out|
45
+ output << out
46
+ end
47
+ output.join
48
+ end
49
+
50
+ def run!
51
+ output = []
52
+ stream! do |out|
53
+ output << out
54
+ end
55
+ output.join
56
+ end
57
+
58
+ def with_full_path
59
+ old_path = ENV['PATH']
60
+ ENV['PATH'] = "#{ENV['PATH']}:#{Shipit::Engine.root.join('lib', 'snippets')}"
61
+ yield
62
+ ensure
63
+ ENV['PATH'] = old_path
64
+ end
65
+
66
+ def interpolated_arguments
67
+ interpolate_environment_variables(@args)
68
+ end
69
+
70
+ def start
71
+ return if @started
72
+ child_in = @out = @pid = nil
73
+ FileUtils.mkdir_p(@chdir)
74
+ with_full_path do
75
+ @out, child_in, @pid = PTY.spawn(@env, *interpolated_arguments, chdir: @chdir)
76
+ child_in.close
77
+ end
78
+ @started = true
79
+ self
80
+ end
81
+
82
+ def stream(&block)
83
+ start
84
+ begin
85
+ read_stream(@out, &block)
86
+ rescue Timeout::Error => error
87
+ @code = 'timeout'
88
+ yield red("No output received in the last #{timeout} seconds.") + "\n"
89
+ terminate!(&block)
90
+ raise error
91
+ rescue Errno::EIO # Somewhat expected on Linux: http://stackoverflow.com/a/10306782
92
+ end
93
+
94
+ _, status = Process.waitpid2(@pid)
95
+ @code = status.exitstatus
96
+ yield exit_message + "\n" unless success?
97
+
98
+ self
99
+ end
100
+
101
+ def check_status
102
+ end
103
+
104
+ def red(text)
105
+ "\033[1;31m#{text}\033[0m"
106
+ end
107
+
108
+ def stream!(&block)
109
+ stream(&block)
110
+ raise Command::Error.new(exit_message) unless success?
111
+ self
112
+ end
113
+
114
+ def read_stream(io)
115
+ loop do
116
+ with_timeout do
117
+ yield io.readpartial(MAX_READ)
118
+ end
119
+ end
120
+ rescue EOFError
121
+ end
122
+
123
+ def with_timeout(&block)
124
+ return yield unless timeout
125
+
126
+ Timeout.timeout(timeout, &block)
127
+ end
128
+
129
+ def terminate!(&block)
130
+ kill_and_wait('INT', 5, &block)
131
+ kill_and_wait('INT', 2, &block)
132
+ kill_and_wait('TERM', 5, &block)
133
+ kill_and_wait('TERM', 2, &block)
134
+ kill('KILL', &block)
135
+ rescue Errno::ECHILD
136
+ true # much success
137
+ ensure
138
+ begin
139
+ read_stream(@out, &block)
140
+ rescue
141
+ end
142
+ end
143
+
144
+ def kill_and_wait(sig, wait, &block)
145
+ kill(sig, &block)
146
+ Timeout.timeout(wait) do
147
+ read_stream(@out, &block)
148
+ end
149
+ rescue Timeout::Error
150
+ end
151
+
152
+ def kill(sig)
153
+ yield red("Sending SIG#{sig} to PID #{@pid}\n")
154
+ Process.kill(sig, @pid)
155
+ end
156
+
157
+ def parse_arguments(arguments)
158
+ options = {}
159
+ args = arguments.flatten.map do |argument|
160
+ case argument
161
+ when Hash
162
+ options.merge!(argument.values.first)
163
+ argument.keys.first
164
+ else
165
+ argument
166
+ end
167
+ end
168
+ return args, options
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,25 @@
1
+ module Shipit
2
+ class Commands
3
+ def self.for(model)
4
+ "#{model.class.name}Commands".constantize.new(model)
5
+ end
6
+
7
+ def self.git_version
8
+ @git_version ||= begin
9
+ `git --version` =~ /([\d\.]+)/
10
+ raise 'git command not found' unless $1
11
+ Gem::Version.new($1)
12
+ end
13
+ end
14
+
15
+ delegate :git_version, to: :class
16
+
17
+ def env
18
+ @env ||= Shipit.env
19
+ end
20
+
21
+ def git(*args)
22
+ Command.new("git", *args)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ module Shipit
2
+ class DeployCommands < TaskCommands
3
+ def steps
4
+ deploy_spec.deploy_steps!
5
+ end
6
+
7
+ def env
8
+ commit = @task.until_commit
9
+ super.merge(
10
+ 'SHA' => commit.sha,
11
+ 'REVISION' => commit.sha,
12
+ )
13
+ end
14
+
15
+ protected
16
+
17
+ def permalink
18
+ Shipit::Engine.routes.url_helpers.stack_deploy_url(@stack, @task)
19
+ end
20
+ end
21
+ end
data/lib/shipit/engine.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Shipit
2
2
  class Engine < ::Rails::Engine
3
+ isolate_namespace Shipit
4
+
3
5
  paths['app/models'] << 'app/serializers' << 'app/serializers/concerns'
4
6
 
5
7
  initializer 'shipit.config' do |app|
@@ -7,6 +9,7 @@ module Shipit
7
9
  Shipit::Engine.routes.default_url_options[:host] = Shipit.host
8
10
 
9
11
  app.config.assets.precompile += %w(
12
+ favicon.ico
10
13
  task.js
11
14
  shipit.js
12
15
  shipit.css
@@ -0,0 +1,7 @@
1
+ module Shipit
2
+ class RollbackCommands < DeployCommands
3
+ def steps
4
+ deploy_spec.rollback_steps!
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,60 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+
4
+ module Shipit
5
+ class StackCommands < Commands
6
+ def initialize(stack)
7
+ @stack = stack
8
+ end
9
+
10
+ def fetch
11
+ create_directories
12
+ if Dir.exist?(@stack.git_path)
13
+ git('fetch', 'origin', '--tags', @stack.branch, env: env, chdir: @stack.git_path)
14
+ else
15
+ git_clone(@stack.repo_git_url, @stack.git_path, branch: @stack.branch, env: env, chdir: @stack.deploys_path)
16
+ end
17
+ end
18
+
19
+ def fetch_deployed_revision
20
+ with_temporary_working_directory do |dir|
21
+ spec = DeploySpec::FileSystem.new(dir, @stack.environment)
22
+ outputs = spec.fetch_deployed_revision_steps!.map do |command_line|
23
+ Command.new(command_line, env: env, chdir: dir).run
24
+ end
25
+ outputs.find(&:present?).try(:strip)
26
+ end
27
+ end
28
+
29
+ def build_cacheable_deploy_spec
30
+ with_temporary_working_directory do |dir|
31
+ DeploySpec::FileSystem.new(dir, @stack.environment).cacheable
32
+ end
33
+ end
34
+
35
+ def with_temporary_working_directory(commit: nil)
36
+ @stack.acquire_git_cache_lock do
37
+ fetch.run!
38
+ git('checkout', '--force', "origin/#{@stack.branch}", env: env, chdir: @stack.git_path).run!
39
+ end
40
+ Dir.mktmpdir do |dir|
41
+ git('clone', @stack.git_path, @stack.repo_name, chdir: dir).run!
42
+ git('checkout', commit.sha, chdir: dir) if commit
43
+ yield Pathname.new(File.join(dir, @stack.repo_name))
44
+ end
45
+ end
46
+
47
+ def git_clone(url, path, branch: 'master', **kwargs)
48
+ git('clone', *modern_git_args, '--recursive', '--branch', branch, url, path, **kwargs)
49
+ end
50
+
51
+ def modern_git_args
52
+ return [] unless git_version >= Gem::Version.new('1.7.10')
53
+ %w(--single-branch)
54
+ end
55
+
56
+ def create_directories
57
+ FileUtils.mkdir_p(@stack.deploys_path)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,68 @@
1
+ module Shipit
2
+ class TaskCommands < Commands
3
+ delegate :fetch, to: :stack_commands
4
+
5
+ def initialize(task)
6
+ @task = task
7
+ @stack = task.stack
8
+ end
9
+
10
+ def deploy_spec
11
+ @deploy_spec ||= DeploySpec::FileSystem.new(@task.working_directory, @stack.environment)
12
+ end
13
+
14
+ def install_dependencies
15
+ deploy_spec.dependencies_steps!.map do |command_line|
16
+ Command.new(command_line, env: env, chdir: steps_directory)
17
+ end
18
+ end
19
+
20
+ def perform
21
+ steps.map do |command_line|
22
+ Command.new(command_line, env: env, chdir: steps_directory)
23
+ end
24
+ end
25
+
26
+ def steps
27
+ @task.definition.steps
28
+ end
29
+
30
+ def env
31
+ normalized_name = ActiveSupport::Inflector.transliterate(@task.author.name)
32
+ super.merge(
33
+ 'ENVIRONMENT' => @stack.environment,
34
+ 'USER' => "#{@task.author.login} (#{normalized_name}) via Shipit",
35
+ 'EMAIL' => @task.author.email,
36
+ 'BUNDLE_PATH' => Rails.root.join('data', 'bundler').to_s,
37
+ 'SHIPIT_LINK' => permalink,
38
+ 'LAST_DEPLOYED_SHA' => @stack.last_deployed_commit.sha,
39
+ ).merge(deploy_spec.machine_env).merge(@task.env)
40
+ end
41
+
42
+ def checkout(commit)
43
+ git('checkout', commit.sha, chdir: @task.working_directory)
44
+ end
45
+
46
+ def clone
47
+ git('clone', '--local', @stack.git_path, @task.working_directory, chdir: @stack.deploys_path)
48
+ end
49
+
50
+ def stack_commands
51
+ @stack_commands = StackCommands.new(@stack)
52
+ end
53
+
54
+ protected
55
+
56
+ def steps_directory
57
+ if sub_directory = deploy_spec.directory.presence
58
+ File.join(@task.working_directory, sub_directory)
59
+ else
60
+ @task.working_directory
61
+ end
62
+ end
63
+
64
+ def permalink
65
+ Shipit::Engine.routes.url_helpers.stack_task_url(@stack, @task)
66
+ end
67
+ end
68
+ end
@@ -1,3 +1,3 @@
1
1
  module Shipit
2
- VERSION = '0.5.2'
2
+ VERSION = '0.6.0'
3
3
  end
data/lib/tasks/cron.rake CHANGED
@@ -1,15 +1,15 @@
1
1
  namespace :cron do
2
2
  desc "Updates deployed revisions"
3
3
  task minutely: :environment do
4
- Stack.refresh_deployed_revisions
4
+ Shipit::Stack.refresh_deployed_revisions
5
5
  end
6
6
 
7
7
  desc "Rolls-up output chunks for completed deploys older than an hour"
8
8
  task rollup: :environment do
9
- Task.due_for_rollup.find_each(&:schedule_rollup_chunks)
9
+ Shipit::Task.due_for_rollup.find_each(&:schedule_rollup_chunks)
10
10
  end
11
11
 
12
12
  task refresh_users: :environment do
13
- User.refresh_shard(Time.now.hour % 24, 24)
13
+ Shipit::User.refresh_shard(Time.now.hour % 24, 24)
14
14
  end
15
15
  end
@@ -1,20 +1,24 @@
1
1
  require 'test_helper'
2
2
 
3
- class Api::BaseControllerTest < ActionController::TestCase
4
- test "authentication is required" do
5
- get :index
6
- assert_response :unauthorized
7
- assert_equal({message: 'Bad credentials'}.to_json, response.body)
8
- end
3
+ module Shipit
4
+ module Api
5
+ class BaseControllerTest < ActionController::TestCase
6
+ test "authentication is required" do
7
+ get :index
8
+ assert_response :unauthorized
9
+ assert_equal({message: 'Bad credentials'}.to_json, response.body)
10
+ end
9
11
 
10
- test "with proper credentials the request is processed" do
11
- authenticate!
12
- assert_response :ok
13
- end
12
+ test "with proper credentials the request is processed" do
13
+ authenticate!
14
+ assert_response :ok
15
+ end
14
16
 
15
- test "#index respond with a list of endpoints" do
16
- authenticate!
17
- get :index, format: :json
18
- assert_equal({stacks_url: api_stacks_url}.to_json, response.body)
17
+ test "#index respond with a list of endpoints" do
18
+ authenticate!
19
+ get :index, format: :json
20
+ assert_equal({stacks_url: api_stacks_url}.to_json, response.body)
21
+ end
22
+ end
19
23
  end
20
24
  end
@@ -1,57 +1,61 @@
1
1
  require 'test_helper'
2
2
 
3
- class Api::DeploysControllerTest < ActionController::TestCase
4
- setup do
5
- authenticate!
6
- @user = users(:walrus)
7
- @stack = stacks(:shipit)
8
- @commit = commits(:fifth)
9
- end
10
-
11
- test "#create triggers a new deploy for the stack" do
12
- assert_difference -> { @stack.deploys.count }, 1 do
13
- post :create, stack_id: @stack.to_param, sha: @commit.sha
14
- end
15
- assert_response :accepted
16
- assert_json 'status', 'pending'
17
- end
18
-
19
- test "#create use the claimed user as author" do
20
- request.headers['X-Shipit-User'] = @user.login
21
- post :create, stack_id: @stack.to_param, sha: @commit.sha
22
- deploy = Deploy.last
23
- deploy.user == @user
24
- end
25
-
26
- test "#create renders a 422 if the sha isn't found" do
27
- post :create, stack_id: @stack.to_param, sha: '123443543545'
28
- assert_response :unprocessable_entity
29
- assert_json 'errors', 'sha' => ['Unknown revision']
30
- end
31
-
32
- test "#create renders a 422 if the sha format is invalid" do
33
- post :create, stack_id: @stack.to_param, sha: '1'
34
- assert_response :unprocessable_entity
35
- assert_json 'errors', 'sha' => ['is too short (minimum is 6 characters)']
36
- end
37
-
38
- test "#create refuses to deploy locked stacks" do
39
- @stack.update!(lock_reason: 'Something broken')
40
-
41
- assert_no_difference -> { @stack.deploys.count } do
42
- post :create, stack_id: @stack.to_param, sha: @commit.sha
43
- end
44
- assert_response :unprocessable_entity
45
- assert_json 'errors.force', ["Can't deploy a locked stack"]
46
- end
47
-
48
- test "#create accepts to deploy locked stacks if force mode is enabled" do
49
- @stack.update!(lock_reason: 'Something broken')
50
-
51
- assert_difference -> { @stack.deploys.count }, 1 do
52
- post :create, stack_id: @stack.to_param, sha: @commit.sha, force: true
3
+ module Shipit
4
+ module Api
5
+ class DeploysControllerTest < ActionController::TestCase
6
+ setup do
7
+ authenticate!
8
+ @user = shipit_users(:walrus)
9
+ @stack = shipit_stacks(:shipit)
10
+ @commit = shipit_commits(:fifth)
11
+ end
12
+
13
+ test "#create triggers a new deploy for the stack" do
14
+ assert_difference -> { @stack.deploys.count }, 1 do
15
+ post :create, stack_id: @stack.to_param, sha: @commit.sha
16
+ end
17
+ assert_response :accepted
18
+ assert_json 'status', 'pending'
19
+ end
20
+
21
+ test "#create use the claimed user as author" do
22
+ request.headers['X-Shipit-User'] = @user.login
23
+ post :create, stack_id: @stack.to_param, sha: @commit.sha
24
+ deploy = Deploy.last
25
+ deploy.user == @user
26
+ end
27
+
28
+ test "#create renders a 422 if the sha isn't found" do
29
+ post :create, stack_id: @stack.to_param, sha: '123443543545'
30
+ assert_response :unprocessable_entity
31
+ assert_json 'errors', 'sha' => ['Unknown revision']
32
+ end
33
+
34
+ test "#create renders a 422 if the sha format is invalid" do
35
+ post :create, stack_id: @stack.to_param, sha: '1'
36
+ assert_response :unprocessable_entity
37
+ assert_json 'errors', 'sha' => ['is too short (minimum is 6 characters)']
38
+ end
39
+
40
+ test "#create refuses to deploy locked stacks" do
41
+ @stack.update!(lock_reason: 'Something broken')
42
+
43
+ assert_no_difference -> { @stack.deploys.count } do
44
+ post :create, stack_id: @stack.to_param, sha: @commit.sha
45
+ end
46
+ assert_response :unprocessable_entity
47
+ assert_json 'errors.force', ["Can't deploy a locked stack"]
48
+ end
49
+
50
+ test "#create accepts to deploy locked stacks if force mode is enabled" do
51
+ @stack.update!(lock_reason: 'Something broken')
52
+
53
+ assert_difference -> { @stack.deploys.count }, 1 do
54
+ post :create, stack_id: @stack.to_param, sha: @commit.sha, force: true
55
+ end
56
+ assert_response :accepted
57
+ assert_json 'status', 'pending'
58
+ end
53
59
  end
54
- assert_response :accepted
55
- assert_json 'status', 'pending'
56
60
  end
57
61
  end