shipit-engine 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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