shipit-engine 0.25.1 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/shipit/merge_status_controller.rb +1 -1
  3. data/app/controllers/shipit/stacks_controller.rb +2 -1
  4. data/app/controllers/shipit/webhooks_controller.rb +15 -0
  5. data/app/jobs/shipit/cache_deploy_spec_job.rb +1 -0
  6. data/app/jobs/shipit/perform_task_job.rb +4 -2
  7. data/app/jobs/shipit/refresh_check_runs_job.rb +14 -0
  8. data/app/models/shipit/check_run.rb +71 -0
  9. data/app/models/shipit/commit.rb +25 -2
  10. data/app/models/shipit/deploy_spec.rb +1 -1
  11. data/app/models/shipit/pull_request.rb +2 -2
  12. data/app/models/shipit/status.rb +1 -1
  13. data/app/views/shipit/commits/_commit.html.erb +1 -1
  14. data/db/migrate/20181010150947_create_shipit_check_runs.rb +17 -0
  15. data/lib/shipit.rb +1 -0
  16. data/lib/shipit/octokit_check_runs.rb +9 -0
  17. data/lib/shipit/stack_commands.rb +8 -3
  18. data/lib/shipit/task_commands.rb +2 -3
  19. data/lib/shipit/version.rb +1 -1
  20. data/test/controllers/merge_status_controller_test.rb +15 -0
  21. data/test/controllers/stacks_controller_test.rb +12 -2
  22. data/test/controllers/webhooks_controller_test.rb +9 -0
  23. data/test/dummy/db/schema.rb +17 -1
  24. data/test/fixtures/payloads/check_suite_master.json +194 -0
  25. data/test/fixtures/shipit/check_runs.yml +21 -0
  26. data/test/fixtures/shipit/commits.yml +13 -0
  27. data/test/fixtures/shipit/stacks.yml +8 -0
  28. data/test/jobs/perform_task_job_test.rb +10 -1
  29. data/test/models/commits_test.rb +29 -2
  30. data/test/models/deploy_spec_test.rb +40 -0
  31. data/test/models/shipit/check_run_test.rb +51 -0
  32. data/test/models/status/group_test.rb +3 -3
  33. data/test/unit/deploy_commands_test.rb +5 -1
  34. metadata +128 -118
@@ -0,0 +1,194 @@
1
+ {
2
+ "action": "requested",
3
+ "check_suite": {
4
+ "id": 5,
5
+ "head_branch": "master",
6
+ "head_sha": "6d9278037b872fd9a6690523e411ecb3aa181355",
7
+ "status": "completed",
8
+ "conclusion": "neutral",
9
+ "url": "https://api.github.com/repos/Shopify/shipit-engine/check-suites/5",
10
+ "before": "146e867f55c26428e5f9fade55a9bbf5e95a7912",
11
+ "after": "d6fde92930d4715a2b49857d24b940956b26d2d3",
12
+ "pull_requests": [
13
+
14
+ ],
15
+ "app": {
16
+ "id": 2,
17
+ "node_id": "MDExOkludGVncmF0aW9uMQ==",
18
+ "owner": {
19
+ "login": "github",
20
+ "id": 340,
21
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=",
22
+ "avatar_url": "http://alambic.github.com/avatars/u/340?",
23
+ "gravatar_id": "",
24
+ "url": "https://api.github.com/users/github",
25
+ "html_url": "http://github.com/github",
26
+ "followers_url": "https://api.github.com/users/github/followers",
27
+ "following_url": "https://api.github.com/users/github/following{/other_user}",
28
+ "gists_url": "https://api.github.com/users/github/gists{/gist_id}",
29
+ "starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}",
30
+ "subscriptions_url": "https://api.github.com/users/github/subscriptions",
31
+ "organizations_url": "https://api.github.com/users/github/orgs",
32
+ "repos_url": "https://api.github.com/users/github/repos",
33
+ "events_url": "https://api.github.com/users/github/events{/privacy}",
34
+ "received_events_url": "https://api.github.com/users/github/received_events",
35
+ "type": "Organization",
36
+ "site_admin": false
37
+ },
38
+ "name": "Super Duper",
39
+ "description": null,
40
+ "external_url": "http://super-duper.example.com",
41
+ "html_url": "http://github.com/apps/super-duper",
42
+ "created_at": "2018-04-25 20:42:10",
43
+ "updated_at": "2018-04-25 20:42:10"
44
+ },
45
+ "created_at": "2018-05-04T01:14:52Z",
46
+ "updated_at": "2018-05-04T01:14:52Z",
47
+ "latest_check_runs_count": 1,
48
+ "check_runs_url": "https://api.github.com/repos/Shopify/shipit-engine/check-suites/5/check-runs",
49
+ "head_commit": {
50
+ "id": "d6fde92930d4715a2b49857d24b940956b26d2d3",
51
+ "tree_id": "41a846c7d878d279f11355e23b348e1bb63b89a8",
52
+ "message": "Say hello (again) to everybody",
53
+ "timestamp": "2018-05-04T01:14:46Z",
54
+ "author": {
55
+ "name": "octocat",
56
+ "email": "octocat@github.com"
57
+ },
58
+ "committer": {
59
+ "name": "octocat",
60
+ "email": "octocat@github.com"
61
+ }
62
+ }
63
+ },
64
+ "repository": {
65
+ "id": 526,
66
+ "node_id": "MDEwOlJlcG9zaXRvcnkxMzU0OTMyMzM=",
67
+ "name": "shipit-engine",
68
+ "full_name": "Shopify/shipit-engine",
69
+ "owner": {
70
+ "login": "github",
71
+ "id": 340,
72
+ "node_id": "MDQ6VXNlcjIxMDMxMDY3",
73
+ "avatar_url": "http://alambic.github.com/avatars/u/340?",
74
+ "gravatar_id": "",
75
+ "url": "https://api.github.com/users/github",
76
+ "html_url": "http://github.com/github",
77
+ "followers_url": "https://api.github.com/users/github/followers",
78
+ "following_url": "https://api.github.com/users/github/following{/other_user}",
79
+ "gists_url": "https://api.github.com/users/github/gists{/gist_id}",
80
+ "starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}",
81
+ "subscriptions_url": "https://api.github.com/users/github/subscriptions",
82
+ "organizations_url": "https://api.github.com/users/github/orgs",
83
+ "repos_url": "https://api.github.com/users/github/repos",
84
+ "events_url": "https://api.github.com/users/github/events{/privacy}",
85
+ "received_events_url": "https://api.github.com/users/github/received_events",
86
+ "type": "Organization",
87
+ "site_admin": false
88
+ },
89
+ "private": false,
90
+ "html_url": "http://github.com/Shopify/shipit-engine",
91
+ "description": null,
92
+ "fork": false,
93
+ "url": "https://api.github.com/repos/Shopify/shipit-engine",
94
+ "forks_url": "https://api.github.com/repos/Shopify/shipit-engine/forks",
95
+ "keys_url": "https://api.github.com/repos/Shopify/shipit-engine/keys{/key_id}",
96
+ "collaborators_url": "https://api.github.com/repos/Shopify/shipit-engine/collaborators{/collaborator}",
97
+ "teams_url": "https://api.github.com/repos/Shopify/shipit-engine/teams",
98
+ "hooks_url": "https://api.github.com/repos/Shopify/shipit-engine/hooks",
99
+ "issue_events_url": "https://api.github.com/repos/Shopify/shipit-engine/issues/events{/number}",
100
+ "events_url": "https://api.github.com/repos/Shopify/shipit-engine/events",
101
+ "assignees_url": "https://api.github.com/repos/Shopify/shipit-engine/assignees{/user}",
102
+ "branches_url": "https://api.github.com/repos/Shopify/shipit-engine/branches{/branch}",
103
+ "tags_url": "https://api.github.com/repos/Shopify/shipit-engine/tags",
104
+ "blobs_url": "https://api.github.com/repos/Shopify/shipit-engine/git/blobs{/sha}",
105
+ "git_tags_url": "https://api.github.com/repos/Shopify/shipit-engine/git/tags{/sha}",
106
+ "git_refs_url": "https://api.github.com/repos/Shopify/shipit-engine/git/refs{/sha}",
107
+ "trees_url": "https://api.github.com/repos/Shopify/shipit-engine/git/trees{/sha}",
108
+ "statuses_url": "https://api.github.com/repos/Shopify/shipit-engine/statuses/{sha}",
109
+ "languages_url": "https://api.github.com/repos/Shopify/shipit-engine/languages",
110
+ "stargazers_url": "https://api.github.com/repos/Shopify/shipit-engine/stargazers",
111
+ "contributors_url": "https://api.github.com/repos/Shopify/shipit-engine/contributors",
112
+ "subscribers_url": "https://api.github.com/repos/Shopify/shipit-engine/subscribers",
113
+ "subscription_url": "https://api.github.com/repos/Shopify/shipit-engine/subscription",
114
+ "commits_url": "https://api.github.com/repos/Shopify/shipit-engine/commits{/sha}",
115
+ "git_commits_url": "https://api.github.com/repos/Shopify/shipit-engine/git/commits{/sha}",
116
+ "comments_url": "https://api.github.com/repos/Shopify/shipit-engine/comments{/number}",
117
+ "issue_comment_url": "https://api.github.com/repos/Shopify/shipit-engine/issues/comments{/number}",
118
+ "contents_url": "https://api.github.com/repos/Shopify/shipit-engine/contents/{+path}",
119
+ "compare_url": "https://api.github.com/repos/Shopify/shipit-engine/compare/{base}...{head}",
120
+ "merges_url": "https://api.github.com/repos/Shopify/shipit-engine/merges",
121
+ "archive_url": "https://api.github.com/repos/Shopify/shipit-engine/{archive_format}{/ref}",
122
+ "downloads_url": "https://api.github.com/repos/Shopify/shipit-engine/downloads",
123
+ "issues_url": "https://api.github.com/repos/Shopify/shipit-engine/issues{/number}",
124
+ "pulls_url": "https://api.github.com/repos/Shopify/shipit-engine/pulls{/number}",
125
+ "milestones_url": "https://api.github.com/repos/Shopify/shipit-engine/milestones{/number}",
126
+ "notifications_url": "https://api.github.com/repos/Shopify/shipit-engine/notifications{?since,all,participating}",
127
+ "labels_url": "https://api.github.com/repos/Shopify/shipit-engine/labels{/name}",
128
+ "releases_url": "https://api.github.com/repos/Shopify/shipit-engine/releases{/id}",
129
+ "deployments_url": "https://api.github.com/repos/Shopify/shipit-engine/deployments",
130
+ "created_at": "2018-04-25T20:42:10Z",
131
+ "updated_at": "2018-04-25T20:43:34Z",
132
+ "pushed_at": "2018-05-04T01:14:47Z",
133
+ "git_url": "git://github.com/Shopify/shipit-engine.git",
134
+ "ssh_url": "ssh://git@localhost:3035/Shopify/shipit-engine.git",
135
+ "clone_url": "http://github.com/Shopify/shipit-engine.git",
136
+ "svn_url": "http://github.com/Shopify/shipit-engine",
137
+ "homepage": null,
138
+ "size": 0,
139
+ "stargazers_count": 0,
140
+ "watchers_count": 0,
141
+ "language": null,
142
+ "has_issues": true,
143
+ "has_projects": true,
144
+ "has_downloads": true,
145
+ "has_wiki": true,
146
+ "has_pages": false,
147
+ "forks_count": 0,
148
+ "mirror_url": null,
149
+ "archived": false,
150
+ "open_issues_count": 3,
151
+ "license": null,
152
+ "forks": 0,
153
+ "open_issues": 3,
154
+ "watchers": 0,
155
+ "default_branch": "master"
156
+ },
157
+ "organization": {
158
+ "login": "github",
159
+ "id": 340,
160
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjM4MzAyODk5",
161
+ "url": "https://api.github.com/orgs/github",
162
+ "repos_url": "https://api.github.com/orgs/github/repos",
163
+ "events_url": "https://api.github.com/orgs/github/events",
164
+ "hooks_url": "https://api.github.com/orgs/github/hooks",
165
+ "issues_url": "https://api.github.com/orgs/github/issues",
166
+ "members_url": "https://api.github.com/orgs/github/members{/member}",
167
+ "public_members_url": "https://api.github.com/orgs/github/public_members{/member}",
168
+ "avatar_url": "http://alambic.github.com/avatars/u/340?",
169
+ "description": "How people build software."
170
+ },
171
+ "sender": {
172
+ "login": "octocat",
173
+ "id": 5346,
174
+ "node_id": "MDQ6VXNlcjIxMDMxMDY3",
175
+ "avatar_url": "http://alambic.github.com/avatars/u/5346?",
176
+ "gravatar_id": "",
177
+ "url": "https://api.github.com/users/octocat",
178
+ "html_url": "http://github.com/octocat",
179
+ "followers_url": "https://api.github.com/users/octocat/followers",
180
+ "following_url": "https://api.github.com/users/octocat/following{/other_user}",
181
+ "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
182
+ "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
183
+ "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
184
+ "organizations_url": "https://api.github.com/users/octocat/orgs",
185
+ "repos_url": "https://api.github.com/users/octocat/repos",
186
+ "events_url": "https://api.github.com/users/octocat/events{/privacy}",
187
+ "received_events_url": "https://api.github.com/users/octocat/received_events",
188
+ "type": "User",
189
+ "site_admin": false
190
+ },
191
+ "installation": {
192
+ "id": 1
193
+ }
194
+ }
@@ -0,0 +1,21 @@
1
+ second_pending_travis:
2
+ stack: shipit
3
+ commit_id: 2 # second
4
+ github_id: 424242
5
+ name: Travis CI
6
+ title: Tests ran successfully
7
+ conclusion: success
8
+ html_url: "http://www.example.com/run/424242"
9
+ details_url: "http://www.example.com/build/424242"
10
+ created_at: <%= 10.days.ago.to_s(:db) %>
11
+
12
+ check_runs_first_success_coveralls:
13
+ stack: check_runs
14
+ commit_id: 201 # check_runs_first
15
+ github_id: 434343
16
+ title: lets go
17
+ name: Coverage metrics
18
+ created_at: <%= 9.days.ago.to_s(:db) %>
19
+ conclusion: success
20
+ html_url: "http://www.example.com/run/434343"
21
+ details_url: "http://www.example.com/build/434343"
@@ -168,3 +168,16 @@ soc_third:
168
168
  additions: 12
169
169
  deletions: 64
170
170
  updated_at: <%= 8.days.ago.to_s(:db) %>
171
+
172
+ check_runs_first:
173
+ id: 201
174
+ sha: 234328037b872fd9a6690523e411ecb3aa181355
175
+ message: "lets go"
176
+ stack: check_runs
177
+ author: walrus
178
+ committer: walrus
179
+ authored_at: <%= 10.days.ago.to_s(:db) %>
180
+ committed_at: <%= 9.days.ago.to_s(:db) %>
181
+ additions: 42
182
+ deletions: 24
183
+ updated_at: <%= 8.days.ago.to_s(:db) %>
@@ -162,3 +162,11 @@ soc:
162
162
  }
163
163
  }
164
164
  updated_at: <%= 8.days.ago.to_s(:db) %>
165
+
166
+ check_runs:
167
+ repo_owner: shopify
168
+ repo_name: check_runs
169
+ environment: production
170
+ branch: master
171
+ tasks_count: 0
172
+ undeployed_commits_count: 1
@@ -2,6 +2,15 @@ require 'test_helper'
2
2
 
3
3
  module Shipit
4
4
  class PerformTaskJobTest < ActiveSupport::TestCase
5
+ class FakeSuccessfulCommand
6
+ def run
7
+ end
8
+
9
+ def success?
10
+ true
11
+ end
12
+ end
13
+
5
14
  setup do
6
15
  @job = PerformTaskJob.new
7
16
  @deploy = shipit_deploys(:shipit_pending)
@@ -14,7 +23,7 @@ module Shipit
14
23
  @commands = stub(:commands)
15
24
  Commands.expects(:for).with(@deploy).returns(@commands)
16
25
 
17
- @commands.expects(:fetch).once
26
+ @commands.expects(:fetched?).once.returns(FakeSuccessfulCommand.new)
18
27
  @commands.expects(:clone).returns([]).once
19
28
  @commands.expects(:checkout).with(@deploy.until_commit).once
20
29
  @commands.expects(:install_dependencies).returns([]).once
@@ -222,6 +222,29 @@ module Shipit
222
222
  assert_equal 'success', @commit.statuses.first.state
223
223
  end
224
224
 
225
+ test "refresh_check_runs! pull state from github" do
226
+ check_run = mock(
227
+ id: 34_234_234_234_432,
228
+ name: 'Test suite',
229
+ conclusion: 'neutral',
230
+ details_url: 'https://example.com/details',
231
+ html_url: 'https://example.com/run',
232
+ output: mock(
233
+ title: 'Tests build ran successfully',
234
+ ),
235
+ )
236
+ response = mock(
237
+ check_runs: [check_run],
238
+ )
239
+ Shipit.github.api.expects(:check_runs).with(@stack.github_repo_name, @commit.sha).returns(response)
240
+
241
+ assert_difference -> { @commit.check_runs.count }, 1 do
242
+ @commit.refresh_check_runs!
243
+ end
244
+
245
+ assert_equal 'success', @commit.check_runs.first.state
246
+ end
247
+
225
248
  test "#creating a commit update the undeployed_commits_count" do
226
249
  walrus = shipit_users(:walrus)
227
250
  assert_equal 1, @stack.undeployed_commits_count
@@ -321,14 +344,18 @@ module Shipit
321
344
  test "#status returns an unknown if the commit has no statuses" do
322
345
  commit = shipit_commits(:second)
323
346
  commit.statuses = []
347
+ commit.check_runs = []
324
348
  assert_predicate commit.status, :unknown?
325
349
  end
326
350
 
327
351
  test "#status rejects the statuses that are specified in the deploy spec's `ci.hide`" do
328
352
  commit = shipit_commits(:second)
329
353
  assert_predicate commit.status, :group?
330
- assert_equal 2, commit.status.size
331
- commit.stack.update!(cached_deploy_spec: DeploySpec.new('ci' => {'hide' => 'metrics/coveralls'}))
354
+ assert_equal 3, commit.status.size
355
+ commit.stack.update!(cached_deploy_spec: DeploySpec.new('ci' => {'hide' => [
356
+ 'Travis CI',
357
+ 'metrics/coveralls',
358
+ ]}))
332
359
  commit.reload
333
360
  refute_predicate commit.status, :group?
334
361
  end
@@ -214,6 +214,46 @@ module Shipit
214
214
  assert_equal ["kubernetes-deploy --max-watch-seconds 900 foo bar"], @spec.rollback_steps
215
215
  end
216
216
 
217
+ test "#discover_task_definitions include a kubernetes restart command if `kubernetes` is present" do
218
+ @spec.stubs(:load_config).returns(
219
+ 'kubernetes' => {
220
+ 'namespace' => 'foo',
221
+ 'context' => 'bar',
222
+ },
223
+ )
224
+ tasks = {
225
+ 'restart' => {
226
+ 'action' => 'Restart application',
227
+ 'description' => 'Simulates a rollout of Kubernetes deployments by using kubernetes-restart utility',
228
+ 'steps' => ['kubernetes-restart foo bar --max-watch-seconds 900'],
229
+ },
230
+ }
231
+ assert_equal tasks, @spec.discover_task_definitions
232
+ end
233
+
234
+ test "#discover_task_definitions include the user defined restart command even if `kubernetes` is present" do
235
+ tasks = {
236
+ 'restart' => {
237
+ 'action' => 'Restart application',
238
+ 'description' => 'Simulates a rollout of Kubernetes deployments by using kubernetes-restart utility',
239
+ 'steps' => ['kubernetes-restart something custom'],
240
+ },
241
+ 'some-other-tasj' => {
242
+ 'action' => 'Do something else',
243
+ 'description' => 'Eat some chips!',
244
+ 'steps' => ['echo chips'],
245
+ },
246
+ }
247
+ @spec.stubs(:load_config).returns(
248
+ 'kubernetes' => {
249
+ 'namespace' => 'foo',
250
+ 'context' => 'bar',
251
+ },
252
+ 'tasks' => tasks,
253
+ )
254
+ assert_equal tasks, @spec.discover_task_definitions
255
+ end
256
+
217
257
  test '#machine_env returns an environment hash' do
218
258
  @spec.stubs(:load_config).returns('machine' => {'environment' => {'GLOBAL' => '1'}})
219
259
  assert_equal({'GLOBAL' => '1'}, @spec.machine_env)
@@ -0,0 +1,51 @@
1
+ require 'test_helper'
2
+
3
+ module Shipit
4
+ class CheckRunTest < ActiveSupport::TestCase
5
+ setup do
6
+ @commit = shipit_commits(:first)
7
+ @stack = @commit.stack
8
+ @check_run = shipit_check_runs(:second_pending_travis)
9
+ end
10
+
11
+ test ".create_or_update_from_github! is idempotent" do
12
+ assert_difference -> { @commit.check_runs.count }, +1 do
13
+ @commit.check_runs.create_or_update_from_github!(@stack.id, github_check_run)
14
+ end
15
+
16
+ assert_no_difference -> { @commit.check_runs.count } do
17
+ @commit.check_runs.create_or_update_from_github!(@stack.id, github_check_run)
18
+ end
19
+ end
20
+
21
+ {
22
+ nil => 'pending',
23
+ 'success' => 'success',
24
+ 'failure' => 'failure',
25
+ 'neutral' => 'success',
26
+ 'cancelled' => 'failure',
27
+ 'timed_out' => 'error',
28
+ 'action_required' => 'pending',
29
+ }.each do |conclusion, expected_status|
30
+ test "#state is #{expected_status.inspect} when conclusion is #{conclusion.inspect}" do
31
+ @check_run.update!(conclusion: conclusion)
32
+ assert_equal expected_status, @check_run.state
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def github_check_run
39
+ @github_check_run ||= OpenStruct.new(
40
+ id: 424_242,
41
+ conclusion: 'success',
42
+ output: OpenStruct.new(
43
+ description: 'This is a description',
44
+ ),
45
+ name: 'Test Suite',
46
+ html_url: 'http://example.com/run',
47
+ details_url: 'http://example.com/details',
48
+ )
49
+ end
50
+ end
51
+ end
@@ -4,11 +4,11 @@ module Shipit
4
4
  class StatusGroupTest < ActiveSupport::TestCase
5
5
  setup do
6
6
  @commit = shipit_commits(:second)
7
- @group = Status::Group.new(@commit, @commit.statuses)
7
+ @group = Status::Group.new(@commit, @commit.statuses_and_check_runs)
8
8
  end
9
9
 
10
10
  test "#description is a summary of the statuses" do
11
- assert_equal '1 / 2 checks OK', @group.description
11
+ assert_equal '2 / 3 checks OK', @group.description
12
12
  end
13
13
 
14
14
  test "#group? returns true" do
@@ -20,7 +20,7 @@ module Shipit
20
20
  end
21
21
 
22
22
  test "#state is significant's status state" do
23
- assert_equal %w(success failure), @group.statuses.map(&:state)
23
+ assert_equal %w(success success failure), @group.statuses.map(&:state)
24
24
  assert_equal 'failure', @group.state
25
25
  end
26
26
 
@@ -61,7 +61,11 @@ module Shipit
61
61
  test "#clone clones the repository cache into the working directory" do
62
62
  commands = @commands.clone
63
63
  assert_equal 2, commands.size
64
- clone_args = ['git', 'clone', '--local', '--origin', 'cache', @stack.git_path, @deploy.working_directory]
64
+ clone_args = [
65
+ 'git', 'clone', '--local',
66
+ '--origin', 'cache',
67
+ @stack.git_path, @deploy.working_directory
68
+ ]
65
69
  assert_equal clone_args, commands.first.args
66
70
  assert_equal ['git', 'remote', 'add', 'origin', @stack.repo_git_url], commands.second.args
67
71
  end