shipit-engine 0.7.0 → 0.8.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +50 -2
  3. data/app/assets/stylesheets/_pages/_deploy.scss +3 -2
  4. data/app/controllers/shipit/api/base_controller.rb +5 -0
  5. data/app/controllers/shipit/api/deploys_controller.rb +2 -1
  6. data/app/controllers/shipit/api/tasks_controller.rb +4 -1
  7. data/app/controllers/shipit/deploys_controller.rb +1 -1
  8. data/app/controllers/shipit/github_authentication_controller.rb +4 -2
  9. data/app/controllers/shipit/rollbacks_controller.rb +1 -1
  10. data/app/controllers/shipit/tasks_controller.rb +14 -2
  11. data/app/helpers/shipit/github_url_helper.rb +4 -2
  12. data/app/helpers/shipit/stacks_helper.rb +3 -3
  13. data/app/jobs/shipit/continuous_delivery_job.rb +12 -0
  14. data/app/jobs/shipit/create_on_github_job.rb +11 -0
  15. data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -1
  16. data/app/models/shipit/anonymous_user.rb +4 -0
  17. data/app/models/shipit/commit.rb +8 -10
  18. data/app/models/shipit/commit_deployment.rb +56 -0
  19. data/app/models/shipit/commit_deployment_status.rb +57 -0
  20. data/app/models/shipit/deploy.rb +32 -6
  21. data/app/models/shipit/deploy_spec.rb +8 -0
  22. data/app/models/shipit/deploy_spec/rubygems_discovery.rb +1 -1
  23. data/app/models/shipit/rollback.rb +10 -0
  24. data/app/models/shipit/stack.rb +30 -12
  25. data/app/models/shipit/status_group.rb +1 -1
  26. data/app/models/shipit/task.rb +1 -0
  27. data/app/models/shipit/task_definition.rb +20 -1
  28. data/app/models/shipit/user.rb +10 -2
  29. data/app/models/shipit/variable_definition.rb +2 -4
  30. data/app/serializers/shipit/commit_serializer.rb +19 -1
  31. data/app/serializers/shipit/deploy_serializer.rb +7 -1
  32. data/app/serializers/shipit/short_commit_serializer.rb +1 -1
  33. data/app/serializers/shipit/task_serializer.rb +17 -1
  34. data/app/views/shipit/_variables.html.erb +15 -0
  35. data/app/views/shipit/deploys/_concurrent_deploy_warning.html.erb +1 -1
  36. data/app/views/shipit/deploys/_deploy.html.erb +2 -2
  37. data/app/views/shipit/deploys/new.html.erb +3 -17
  38. data/app/views/shipit/deploys/rollback.html.erb +3 -17
  39. data/app/views/shipit/tasks/new.html.erb +12 -4
  40. data/config/locales/en.yml +11 -0
  41. data/db/migrate/20160210183823_add_allow_concurrency_to_tasks.rb +5 -0
  42. data/db/migrate/20160303163611_create_shipit_commit_deployments.rb +14 -0
  43. data/db/migrate/20160303170913_create_shipit_commit_deployment_statuses.rb +12 -0
  44. data/db/migrate/20160303203940_add_encrypted_token_to_users.rb +6 -0
  45. data/lib/shipit.rb +7 -1
  46. data/lib/shipit/engine.rb +3 -1
  47. data/lib/shipit/environment_variables.rb +34 -0
  48. data/lib/shipit/simple_message_verifier.rb +0 -1
  49. data/lib/shipit/task_commands.rb +1 -0
  50. data/lib/shipit/version.rb +1 -1
  51. data/test/controllers/api/deploys_controller_test.rb +15 -0
  52. data/test/controllers/api/tasks_controller_test.rb +15 -0
  53. data/test/controllers/github_authentication_controller_test.rb +23 -5
  54. data/test/controllers/tasks_controller_test.rb +27 -2
  55. data/test/controllers/webhooks_controller_test.rb +8 -2
  56. data/test/dummy/config/database.mysql.yml +1 -1
  57. data/test/dummy/config/secrets.example.yml +2 -2
  58. data/test/dummy/config/secrets.yml +2 -2
  59. data/test/dummy/data/stacks/byroot/junk/production/git/bar.txt +1 -0
  60. data/test/dummy/data/stacks/byroot/junk/production/git/dkfdsf +0 -0
  61. data/test/dummy/data/stacks/byroot/junk/production/git/dskjfsd +0 -0
  62. data/test/dummy/data/stacks/byroot/junk/production/git/dslkjfjsdf +0 -0
  63. data/test/dummy/data/stacks/byroot/junk/production/git/plopfizz +0 -0
  64. data/test/dummy/data/stacks/byroot/junk/production/git/sd +0 -0
  65. data/test/dummy/data/stacks/byroot/junk/production/git/sdkfjsdf +1 -0
  66. data/test/dummy/data/stacks/byroot/junk/production/git/sdlfjsdfdsfj +0 -0
  67. data/test/dummy/data/stacks/byroot/junk/production/git/sdlkfjsdlkfjsdlkfjdsfsdfksdfjsldkfjsdlkfjsdf +0 -0
  68. data/test/dummy/data/stacks/byroot/junk/production/git/shipit.yml +27 -0
  69. data/test/dummy/data/stacks/byroot/junk/production/git/toto.txt +2 -0
  70. data/test/dummy/db/development.sqlite3 +0 -0
  71. data/test/dummy/db/schema.rb +35 -7
  72. data/test/dummy/db/seeds.rb +3 -0
  73. data/test/dummy/db/test.sqlite3 +0 -0
  74. data/test/fixtures/shipit/commit_deployment_statuses.yml +19 -0
  75. data/test/fixtures/shipit/commit_deployments.yml +37 -0
  76. data/test/fixtures/shipit/commits.yml +1 -1
  77. data/test/fixtures/shipit/stacks.yml +12 -0
  78. data/test/fixtures/shipit/tasks.yml +4 -0
  79. data/test/fixtures/shipit/users.yml +2 -0
  80. data/test/jobs/fetch_deployed_revision_job_test.rb +3 -3
  81. data/test/models/commit_deployment_status_test.rb +27 -0
  82. data/test/models/commit_deployment_test.rb +37 -0
  83. data/test/models/commits_test.rb +7 -4
  84. data/test/models/deploys_test.rb +17 -1
  85. data/test/models/stacks_test.rb +13 -13
  86. data/test/models/task_definitions_test.rb +10 -0
  87. data/test/models/team_test.rb +8 -2
  88. data/test/models/users_test.rb +20 -2
  89. data/test/unit/deploy_spec_test.rb +29 -0
  90. data/test/unit/environment_variables_test.rb +36 -0
  91. data/test/unit/github_url_helper_test.rb +0 -8
  92. metadata +76 -20
@@ -0,0 +1,27 @@
1
+ review:
2
+ checklist:
3
+ - Blah Blah
4
+ checks:
5
+ - echo 42
6
+
7
+ deploy:
8
+ variables:
9
+ -
10
+ name: REBUILD
11
+ title: Force artifacts rebuild
12
+ default: '0'
13
+ override:
14
+ - echo 1
15
+ - sleep 10
16
+
17
+ rollback:
18
+ override:
19
+ - echo done
20
+
21
+
22
+ tasks:
23
+ restart:
24
+ action: Restart application
25
+ description: Trigger the restart of both app and jobs servers
26
+ steps:
27
+ - cap $ENVIRONMENT deploy:restart
Binary file
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 20160122165559) do
14
+ ActiveRecord::Schema.define(version: 20160303203940) do
15
15
 
16
16
  create_table "api_clients", force: :cascade do |t|
17
17
  t.text "permissions", limit: 65535
@@ -24,6 +24,29 @@ ActiveRecord::Schema.define(version: 20160122165559) do
24
24
 
25
25
  add_index "api_clients", ["creator_id"], name: "index_api_clients_on_creator_id"
26
26
 
27
+ create_table "commit_deployment_statuses", force: :cascade do |t|
28
+ t.integer "commit_deployment_id"
29
+ t.string "status"
30
+ t.integer "github_id"
31
+ t.string "api_url"
32
+ t.datetime "created_at", null: false
33
+ t.datetime "updated_at", null: false
34
+ end
35
+
36
+ add_index "commit_deployment_statuses", ["commit_deployment_id"], name: "index_commit_deployment_statuses_on_commit_deployment_id"
37
+
38
+ create_table "commit_deployments", force: :cascade do |t|
39
+ t.integer "commit_id"
40
+ t.integer "task_id"
41
+ t.integer "github_id"
42
+ t.string "api_url"
43
+ t.datetime "created_at", null: false
44
+ t.datetime "updated_at", null: false
45
+ end
46
+
47
+ add_index "commit_deployments", ["commit_id", "task_id"], name: "index_commit_deployments_on_commit_id_and_task_id", unique: true
48
+ add_index "commit_deployments", ["task_id"], name: "index_commit_deployments_on_task_id"
49
+
27
50
  create_table "commits", force: :cascade do |t|
28
51
  t.integer "stack_id", limit: 4, null: false
29
52
  t.integer "author_id", limit: 4, null: false
@@ -156,11 +179,14 @@ ActiveRecord::Schema.define(version: 20160122165559) do
156
179
  t.boolean "rollback_once_aborted", default: false, null: false
157
180
  t.text "env"
158
181
  t.integer "confirmations", default: 0, null: false
182
+ t.boolean "allow_concurrency", default: false, null: false
159
183
  end
160
184
 
161
185
  add_index "tasks", ["rolled_up", "created_at", "status"], name: "index_tasks_on_rolled_up_and_created_at_and_status"
162
186
  add_index "tasks", ["since_commit_id"], name: "index_tasks_on_since_commit_id"
163
187
  add_index "tasks", ["stack_id"], name: "index_tasks_on_stack_id"
188
+ add_index "tasks", ["type", "stack_id", "parent_id"], name: "index_tasks_by_stack_and_parent"
189
+ add_index "tasks", ["type", "stack_id", "status"], name: "index_tasks_by_stack_and_status"
164
190
  add_index "tasks", ["until_commit_id"], name: "index_tasks_on_until_commit_id"
165
191
  add_index "tasks", ["user_id"], name: "index_tasks_on_user_id"
166
192
 
@@ -177,14 +203,16 @@ ActiveRecord::Schema.define(version: 20160122165559) do
177
203
  add_index "teams", ["organization", "slug"], name: "index_teams_on_organization_and_slug", unique: true
178
204
 
179
205
  create_table "users", force: :cascade do |t|
180
- t.integer "github_id", limit: 4
181
- t.string "name", limit: 255, null: false
182
- t.string "email", limit: 255
183
- t.string "login", limit: 39
184
- t.string "api_url", limit: 255
206
+ t.integer "github_id", limit: 4
207
+ t.string "name", limit: 255, null: false
208
+ t.string "email", limit: 255
209
+ t.string "login", limit: 39
210
+ t.string "api_url", limit: 255
185
211
  t.datetime "created_at"
186
212
  t.datetime "updated_at"
187
- t.string "avatar_url", limit: 255
213
+ t.string "avatar_url", limit: 255
214
+ t.string "encrypted_github_access_token"
215
+ t.string "encrypted_github_access_token_iv"
188
216
  end
189
217
 
190
218
  add_index "users", ["login"], name: "index_users_on_login"
@@ -51,6 +51,9 @@ module Shipit
51
51
  "steps": [
52
52
  "bundle exec cap $ENVIRONMENT deploy:restart"
53
53
  ],
54
+ "variables": [
55
+ {"name": "SAFETY_DISABLED", "title": "Set to 1 to do stuff", "default": "0"}
56
+ ],
54
57
  "checklist": [
55
58
  "Hold on your butts",
56
59
  "Eat some chips"
Binary file
@@ -0,0 +1,19 @@
1
+ shipit_deploy_second_pending:
2
+ commit_deployment: shipit_deploy_second
3
+ status: pending
4
+ github_id: 42
5
+ api_url: https://api.github.com/repos/shopify/shipit-engine/deployments/1/statuses/42
6
+
7
+ shipit_deploy_second_success:
8
+ commit_deployment: shipit_deploy_second
9
+ status: success
10
+ github_id: 43
11
+ api_url: https://api.github.com/repos/shopify/shipit-engine/deployments/1/statuses/43
12
+
13
+ shipit2_deploy_third_pending:
14
+ commit_deployment: shipit2_deploy_third
15
+ status: pending
16
+
17
+ shipit2_deploy_third_failure:
18
+ commit_deployment: shipit2_deploy_third
19
+ status: failure
@@ -0,0 +1,37 @@
1
+ shipit_deploy_second:
2
+ commit_id: 2 # second
3
+ task: shipit
4
+ api_url: https://api.github.com/repos/shopify/shipit-engine/deployments/1
5
+ github_id: 1
6
+
7
+ shipit2_deploy_third:
8
+ commit_id: 3 # third
9
+ task: shipit2
10
+ api_url: https://api.github.com/repos/shopify/shipit-engine/deployments/2
11
+ github_id: 2
12
+
13
+ shipit_pending_third:
14
+ commit_id: 3 # third
15
+ task: shipit_pending
16
+ api_url: https://api.github.com/repos/shopify/shipit-engine/deployments/3
17
+ github_id: 3
18
+
19
+ shipit_pending_fourth:
20
+ commit_id: 4 # fourth
21
+ task: shipit_pending
22
+
23
+ shipit_running_fourth:
24
+ commit_id: 4 # fourth
25
+ task: shipit_running
26
+
27
+ shipit_complete_fourth:
28
+ commit_id: 4 # fourth
29
+ task: shipit_complete
30
+
31
+ shipit_aborted_fourth:
32
+ commit_id: 4 # fourth
33
+ task: shipit_aborted
34
+
35
+ shipit_rollback_fourth:
36
+ commit_id: 4 # fourth
37
+ task: shipit_rollback
@@ -40,7 +40,7 @@ third:
40
40
  fourth:
41
41
  id: 4
42
42
  sha: 467578b362bf2b4df5903e1c7960929361c3435a
43
- message: "#yoloshipit!"
43
+ message: "Merge pull request #7 from shipit-engine/yoloshipit\n\nyoloshipit!"
44
44
  stack: shipit
45
45
  author: walrus
46
46
  committer: walrus
@@ -23,9 +23,21 @@ shipit:
23
23
  "restart": {
24
24
  "action": "Restart application",
25
25
  "description": "Restart app and job servers",
26
+ "variables": [
27
+ {"name": "FOO", "title": "Set to 0 to foo", "default": 1},
28
+ {"name": "BAR", "title": "Set to 1 to bar", "default": 0}
29
+ ],
26
30
  "steps": [
27
31
  "cap $ENVIRONMENT deploy:restart"
28
32
  ]
33
+ },
34
+ "flush_cache": {
35
+ "action": "Flush cache",
36
+ "description": "Flush the application cache",
37
+ "steps": [
38
+ "cap $ENVIRONMENT cache:flush"
39
+ ],
40
+ "allow_concurrency": true
29
41
  }
30
42
  },
31
43
  "ci": {
@@ -32,6 +32,10 @@ shipit_restart:
32
32
  "id": "restart",
33
33
  "action": "Restart application",
34
34
  "description": "Restart app and job servers",
35
+ "variables": [
36
+ {"name": "FOO", "title": "Set to 0 to foo", "default": 1},
37
+ {"name": "BAR", "title": "Set to 1 to bar", "default": 0}
38
+ ],
35
39
  "steps": [
36
40
  "cap $ENVIRONMENT deploy:restart"
37
41
  ]
@@ -2,6 +2,8 @@ walrus:
2
2
  name: Lando Walrussian
3
3
  email: walrus@shopify.com
4
4
  login: walrus
5
+ encrypted_github_access_token: FuQv9jpHmMZ8Px64xmqASJtKlefv # t0k3n
6
+ encrypted_github_access_token_iv: "QNS4smChXEXtOjxb\n"
5
7
 
6
8
  bob:
7
9
  name: Bob the Builder
@@ -9,21 +9,21 @@ module Shipit
9
9
  end
10
10
 
11
11
  test 'the job abort if the stack is deploying' do
12
- @stack.expects(:deploying?).returns(true)
12
+ @stack.expects(:active_task?).returns(true)
13
13
  assert_no_difference 'Deploy.count' do
14
14
  @job.perform(@stack)
15
15
  end
16
16
  end
17
17
 
18
18
  test 'the job abort if #fetch_deployed_revision returns nil' do
19
- @stack.expects(:deploying?).returns(false)
19
+ @stack.expects(:active_task?).returns(false)
20
20
  StackCommands.any_instance.expects(:fetch_deployed_revision).returns(nil)
21
21
  @stack.expects(:update_deployed_revision).never
22
22
  @job.perform(@stack)
23
23
  end
24
24
 
25
25
  test 'the job call update_deployed_revision if #fetch_deployed_revision returns something' do
26
- @stack.expects(:deploying?).returns(false)
26
+ @stack.expects(:active_task?).returns(false)
27
27
  StackCommands.any_instance.expects(:fetch_deployed_revision).returns(@commit.sha)
28
28
  @stack.expects(:update_deployed_revision).with(@commit.sha)
29
29
  @job.perform(@stack)
@@ -0,0 +1,27 @@
1
+ require 'test_helper'
2
+
3
+ module Shipit
4
+ class CommitDeploymentStatusTest < ActiveSupport::TestCase
5
+ setup do
6
+ @status = shipit_commit_deployment_statuses(:shipit2_deploy_third_pending)
7
+ @deployment = @status.commit_deployment
8
+ @task = @deployment.task
9
+ @commit = @deployment.commit
10
+ @author = @deployment.author
11
+ end
12
+
13
+ test 'creation on GitHub' do
14
+ response = stub(id: 44, url: 'https://example.com')
15
+ @author.github_api.expects(:create_deployment_status).with(
16
+ @deployment.api_url,
17
+ 'pending',
18
+ target_url: "http://shipit.com/shopify/shipit-engine/production/deploys/#{@task.id}",
19
+ description: "walrus triggered the deploy of shopify/shipit-engine/production to #{@commit.sha}",
20
+ ).returns(response)
21
+
22
+ @status.create_on_github!
23
+ assert_equal response.id, @status.github_id
24
+ assert_equal response.url, @status.api_url
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ module Shipit
4
+ class CommitDeploymentTest < ActiveSupport::TestCase
5
+ setup do
6
+ @deployment = shipit_commit_deployments(:shipit_pending_fourth)
7
+ @commit = @deployment.commit
8
+ @task = @deployment.task
9
+ @stack = @task.stack
10
+ @author = @deployment.author
11
+ end
12
+
13
+ test "there can only be one record per deploy and commit pair" do
14
+ assert_raises ActiveRecord::RecordNotUnique do
15
+ CommitDeployment.create!(task: @deployment.task, commit: @deployment.commit)
16
+ end
17
+ end
18
+
19
+ test "creation on GitHub" do
20
+ pull_request_response = stub(head: stub(sha: '6dcb09b5b57875f334f61aebed695e2e4193db5e'))
21
+ @author.github_api.expects(:pull_request).with('shopify/shipit-engine', 7).returns(pull_request_response)
22
+
23
+ deployment_response = stub(id: 42, url: 'https://example.com')
24
+ @author.github_api.expects(:create_deployment).with(
25
+ 'shopify/shipit-engine',
26
+ pull_request_response.head.sha,
27
+ auto_merge: false,
28
+ description: "Via Shipit",
29
+ environment: @stack.environment,
30
+ ).returns(deployment_response)
31
+
32
+ @deployment.create_on_github!
33
+ assert_equal deployment_response.id, @deployment.github_id
34
+ assert_equal deployment_response.url, @deployment.api_url
35
+ end
36
+ end
37
+ end
@@ -20,9 +20,9 @@ module Shipit
20
20
  assert_equal "Bump to v1.0.1", @pr.pull_request_title
21
21
  end
22
22
 
23
- test "#pull_request_id extract the pull request id from the message" do
24
- assert_equal 31, @pr.pull_request_id
25
- assert_nil @commit.pull_request_id
23
+ test "#pull_request_number extract the pull request id from the message" do
24
+ assert_equal 31, @pr.pull_request_number
25
+ assert_nil @commit.pull_request_number
26
26
  end
27
27
 
28
28
  test "#pull_request_title extract the pull request title from the message" do
@@ -69,7 +69,10 @@ module Shipit
69
69
  @stack.deploys.destroy_all
70
70
 
71
71
  assert_difference "Deploy.count" do
72
- @stack.commits.last.statuses.create!(state: 'success', context: 'ci/travis')
72
+ assert_enqueued_with(job: ContinuousDeliveryJob, args: [@stack]) do
73
+ @stack.commits.last.statuses.create!(state: 'success', context: 'ci/travis')
74
+ end
75
+ ContinuousDeliveryJob.new.perform(@stack)
73
76
  end
74
77
  end
75
78
 
@@ -148,10 +148,14 @@ module Shipit
148
148
  shipit_commits(:fifth).statuses.create!(state: 'success')
149
149
 
150
150
  deploy = shipit_deploys(:shipit_running)
151
+ deploy.stack.tasks.where.not(id: deploy.id).update_all(status: 'success')
151
152
  deploy.stack.update(continuous_deployment: true)
152
153
 
153
154
  assert_difference "Deploy.count" do
154
- deploy.complete!
155
+ assert_enqueued_with(job: ContinuousDeliveryJob, args: [deploy.stack]) do
156
+ deploy.complete!
157
+ end
158
+ ContinuousDeliveryJob.new.perform(deploy.stack)
155
159
  end
156
160
  end
157
161
 
@@ -207,6 +211,18 @@ module Shipit
207
211
  end
208
212
  end
209
213
 
214
+ test "creating a deploy creates one CommitDeployment per commit" do
215
+ shipit = shipit_stacks(:shipit)
216
+ deploy = shipit.deploys.build(
217
+ since_commit: shipit.commits.first,
218
+ until_commit: shipit.commits.last,
219
+ )
220
+
221
+ assert_difference -> { CommitDeployment.count }, deploy.commits.size do
222
+ deploy.save!
223
+ end
224
+ end
225
+
210
226
  test "#build_rollback returns an unsaved record" do
211
227
  assert @deploy.build_rollback.new_record?
212
228
  end
@@ -205,39 +205,39 @@ module Shipit
205
205
  shipit_stacks(:shipit).destroy
206
206
  end
207
207
 
208
- test "#deploying? is false if stack has no deploy in either pending or running state" do
208
+ test "#active_task? is false if stack has no deploy in either pending or running state" do
209
209
  @stack.deploys.active.destroy_all
210
- refute @stack.deploying?
210
+ refute @stack.active_task?
211
211
  end
212
212
 
213
- test "#deploying? is false if stack has no deploy at all" do
213
+ test "#active_task? is false if stack has no deploy at all" do
214
214
  @stack.deploys.destroy_all
215
- refute @stack.deploying?
215
+ refute @stack.active_task?
216
216
  end
217
217
 
218
- test "#deploying? is true if stack has a deploy in either pending or running state" do
218
+ test "#active_task? is true if stack has a deploy in either pending or running state" do
219
219
  @stack.trigger_deploy(shipit_commits(:third), AnonymousUser.new)
220
- assert @stack.deploying?
220
+ assert @stack.active_task?
221
221
  end
222
222
 
223
- test "#deploying? is true if a rollback is ongoing" do
223
+ test "#active_task? is true if a rollback is ongoing" do
224
224
  shipit_deploys(:shipit_complete).trigger_rollback(AnonymousUser.new)
225
- assert @stack.deploying?
225
+ assert @stack.active_task?
226
226
  end
227
227
 
228
- test "#deploying? is memoized" do
228
+ test "#active_task? is memoized" do
229
229
  assert_queries(1) do
230
- 10.times { @stack.deploying? }
230
+ 10.times { @stack.active_task? }
231
231
  end
232
232
  end
233
233
 
234
- test "#deploying? cache is cleared if a deploy change state" do
234
+ test "#active_task? cache is cleared if a deploy change state" do
235
235
  assert_queries(1) do
236
- 10.times { @stack.deploying? }
236
+ 10.times { @stack.active_task? }
237
237
  end
238
238
  @stack.tasks.where(status: 'running').first.error!
239
239
  assert_queries(1) do
240
- 10.times { @stack.deploying? }
240
+ 10.times { @stack.active_task? }
241
241
  end
242
242
  end
243
243