shipit-engine 0.35.1 → 0.37.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -7
  3. data/app/controllers/concerns/shipit/authentication.rb +5 -1
  4. data/app/controllers/shipit/api/base_controller.rb +13 -1
  5. data/app/controllers/shipit/api/rollbacks_controller.rb +1 -1
  6. data/app/controllers/shipit/api/stacks_controller.rb +10 -2
  7. data/app/controllers/shipit/api/tasks_controller.rb +19 -2
  8. data/app/controllers/shipit/rollbacks_controller.rb +5 -1
  9. data/app/helpers/shipit/stacks_helper.rb +11 -0
  10. data/app/models/concerns/shipit/deferred_touch.rb +3 -3
  11. data/app/models/shipit/anonymous_user.rb +4 -0
  12. data/app/models/shipit/api_client.rb +1 -1
  13. data/app/models/shipit/commit_checks.rb +3 -3
  14. data/app/models/shipit/delivery.rb +1 -1
  15. data/app/models/shipit/deploy.rb +1 -0
  16. data/app/models/shipit/deploy_spec/file_system.rb +32 -4
  17. data/app/models/shipit/pull_request.rb +1 -1
  18. data/app/models/shipit/stack.rb +10 -10
  19. data/app/models/shipit/task.rb +31 -4
  20. data/app/models/shipit/user.rb +23 -9
  21. data/app/serializers/shipit/stack_serializer.rb +1 -1
  22. data/app/views/shipit/deploys/_deploy.html.erb +1 -5
  23. data/app/views/shipit/stacks/_banners.html.erb +1 -1
  24. data/app/views/shipit/stacks/_settings_form.erb +55 -0
  25. data/app/views/shipit/stacks/settings.html.erb +1 -55
  26. data/app/views/shipit/stacks/show.html.erb +1 -1
  27. data/config/locales/en.yml +1 -1
  28. data/config/routes.rb +4 -0
  29. data/db/migrate/20211103154121_increase_github_team_slug_size.rb +5 -0
  30. data/lib/shipit/engine.rb +15 -5
  31. data/lib/shipit/stack_commands.rb +9 -2
  32. data/lib/shipit/task_commands.rb +8 -1
  33. data/lib/shipit/version.rb +1 -1
  34. data/lib/shipit.rb +55 -3
  35. data/lib/snippets/fetch-gem-version +1 -1
  36. data/test/controllers/api/hooks_controller_test.rb +1 -1
  37. data/test/controllers/api/rollback_controller_test.rb +1 -0
  38. data/test/controllers/api/stacks_controller_test.rb +34 -0
  39. data/test/controllers/api/tasks_controller_test.rb +56 -0
  40. data/test/controllers/stacks_controller_test.rb +11 -0
  41. data/test/dummy/config/application.rb +1 -2
  42. data/test/dummy/db/schema.rb +2 -2
  43. data/test/fixtures/shipit/check_runs.yml +3 -3
  44. data/test/fixtures/shipit/commits.yml +101 -101
  45. data/test/fixtures/shipit/deliveries.yml +1 -1
  46. data/test/fixtures/shipit/merge_requests.yml +19 -19
  47. data/test/fixtures/shipit/stacks.yml +28 -28
  48. data/test/fixtures/shipit/statuses.yml +16 -16
  49. data/test/fixtures/shipit/tasks.yml +77 -65
  50. data/test/fixtures/shipit/users.yml +2 -5
  51. data/test/models/commits_test.rb +6 -6
  52. data/test/models/deploy_spec_test.rb +0 -23
  53. data/test/models/deploys_test.rb +26 -0
  54. data/test/models/shipit/deploy_spec/file_system_test.rb +81 -0
  55. data/test/models/tasks_test.rb +14 -2
  56. data/test/models/team_test.rb +21 -2
  57. data/test/models/users_test.rb +29 -9
  58. data/test/unit/deploy_commands_test.rb +6 -2
  59. metadata +189 -185
@@ -459,6 +459,32 @@ module Shipit
459
459
  end
460
460
  end
461
461
 
462
+ test "transitioning to aborted locks the stack if a rollback is scheduled" do
463
+ refute @stack.locked?
464
+
465
+ @deploy = shipit_deploys(:shipit_running)
466
+ @deploy.ping
467
+ @deploy.pid = 42
468
+ @deploy.abort!(rollback_once_aborted: true, aborted_by: @user)
469
+ @deploy.aborted!
470
+
471
+ assert_predicate @stack.reload, :locked?
472
+ assert_equal @user, @stack.lock_author
473
+ end
474
+
475
+ test "transitioning to aborted emits a lock hook if a rollback is scheduled" do
476
+ refute_predicate @stack, :locked?
477
+
478
+ @deploy = shipit_deploys(:shipit_running)
479
+ @deploy.ping
480
+ @deploy.pid = 42
481
+ @deploy.abort!(rollback_once_aborted: true, aborted_by: @user)
482
+
483
+ expect_hook(:lock, @stack, locked: true, lock_details: nil, stack: @stack) do
484
+ @deploy.aborted!
485
+ end
486
+ end
487
+
462
488
  test "#build_rollback returns an unsaved record" do
463
489
  assert @deploy.build_rollback.new_record?
464
490
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+ require 'tmpdir'
4
+
5
+ module Shipit
6
+ class DeploySpec
7
+ class FileSystemTest < ActiveSupport::TestCase
8
+ test 'deploy.pre calls "exit 1" if there is a bare shipit file and Shipit is configured to ignore' do
9
+ Shipit.expects(:respect_bare_shipit_file?).returns(false).at_least_once
10
+ deploy_spec = Shipit::DeploySpec::FileSystem.new(Dir.tmpdir, 'env')
11
+ deploy_spec.expects(:config_file_path).returns(Pathname.new(Dir.tmpdir) + '/shipit.yml').at_least_once
12
+ deploy_spec.expects(:read_config).never
13
+ pre_commands = deploy_spec.send(:config, 'deploy', 'pre')
14
+ assert pre_commands.include?('exit 1')
15
+ assert pre_commands.first.include?('configured to ignore')
16
+ refute pre_commands.include?('test 2')
17
+ end
18
+
19
+ test 'deploy.pre does not call "exit 1" if Shipit is not configured to do so' do
20
+ Shipit.expects(:respect_bare_shipit_file?).returns(true).at_least_once
21
+ deploy_spec = Shipit::DeploySpec::FileSystem.new(Dir.tmpdir, 'env')
22
+ deploy_spec.expects(:config_file_path).returns(Pathname.new(Dir.tmpdir) + '/shipit.yml').at_least_once
23
+ deploy_spec.expects(:read_config).returns(SafeYAML.load(deploy_spec_yaml))
24
+ pre_commands = deploy_spec.send(:config, 'deploy', 'pre')
25
+ refute pre_commands.include?('exit 1')
26
+ assert pre_commands.include?('test 2')
27
+ end
28
+
29
+ test 'Shipit.respect_bare_shipit_file? has no effect if the file is not a bare file' do
30
+ [true, false].each do |obey_val|
31
+ Shipit.expects(:respect_bare_shipit_file?).returns(obey_val).at_least_once
32
+ deploy_spec = Shipit::DeploySpec::FileSystem.new(Dir.tmpdir, 'env')
33
+ deploy_spec.expects(:config_file_path).returns(Pathname.new(Dir.tmpdir) + '/shipit.env.yml').at_least_once
34
+ deploy_spec.expects(:read_config).returns(SafeYAML.load(deploy_spec_yaml))
35
+ pre_commands = deploy_spec.send(:config, 'deploy', 'pre')
36
+ refute pre_commands.include?('exit 1')
37
+ assert pre_commands.include?('test 2')
38
+ end
39
+ end
40
+
41
+ test '#load_config does not error if the file is empty' do
42
+ Shipit.expects(:respect_bare_shipit_file?).returns(true).at_least_once
43
+ deploy_spec = Shipit::DeploySpec::FileSystem.new(Dir.tmpdir, 'env')
44
+ deploy_spec.expects(:config_file_path).returns(Pathname.new(Dir.tmpdir) + '/shipit.env.yml').at_least_once
45
+ deploy_spec.expects(:read_config).at_least_once.returns(false)
46
+ loaded_config = deploy_spec.send(:cacheable_config)
47
+ refute loaded_config == false
48
+ end
49
+
50
+ test '#load_config does not error if there is no "deploy" key' do
51
+ Shipit.expects(:respect_bare_shipit_file?).returns(false).at_least_once
52
+ deploy_spec = Shipit::DeploySpec::FileSystem.new(Dir.tmpdir, 'env')
53
+ deploy_spec.expects(:config_file_path).returns(Pathname.new(Dir.tmpdir) + '/shipit.yml').at_least_once
54
+ deploy_spec.expects(:read_config).never
55
+ loaded_config = deploy_spec.send(:load_config)
56
+ assert loaded_config.key?("deploy")
57
+ assert loaded_config["deploy"].key?("pre")
58
+ assert loaded_config["deploy"]["pre"].include?('exit 1')
59
+ end
60
+
61
+ def deploy_spec_yaml
62
+ <<~EOYAML
63
+ deploy:
64
+ pre:
65
+ - test 2
66
+ override:
67
+ - test 1
68
+ EOYAML
69
+ end
70
+
71
+ def deploy_spec_missing_deploy_yaml
72
+ <<~EOYAML
73
+ production_platform:
74
+ application: test-application
75
+ runtime_ids:
76
+ - production-unrestricted-1234
77
+ EOYAML
78
+ end
79
+ end
80
+ end
81
+ end
@@ -93,7 +93,7 @@ module Shipit
93
93
  task = shipit_tasks(:shipit)
94
94
  task.update(
95
95
  rolled_up: false,
96
- created_at: (60 + 1).minutes.ago.to_s(:db),
96
+ created_at: (60 + 1).minutes.ago.to_formatted_s(:db),
97
97
  status: "success",
98
98
  )
99
99
 
@@ -104,11 +104,23 @@ module Shipit
104
104
  task = shipit_tasks(:shipit)
105
105
  task.update(
106
106
  rolled_up: false,
107
- created_at: (60 + 1).minutes.ago.to_s(:db),
107
+ created_at: (60 + 1).minutes.ago.to_formatted_s(:db),
108
108
  status: "error",
109
109
  )
110
110
 
111
111
  assert_includes Shipit::Task.due_for_rollup, task
112
112
  end
113
+
114
+ test "load legacy YAML records" do
115
+ task = Shipit::Task.find(shipit_tasks(:shipit_legacy_yaml_task).id)
116
+ assert_equal({ "POD_ID" => "12" }, task.env)
117
+ assert_equal Hash, task.env.class
118
+
119
+ task.save
120
+ task.reload
121
+
122
+ assert_equal({ "POD_ID" => "12" }, task.env)
123
+ assert_equal Hash, task.env.class
124
+ end
113
125
  end
114
126
  end
@@ -29,6 +29,25 @@ module Shipit
29
29
  end
30
30
  end
31
31
 
32
+ test ".find_or_create_by_handle accepts large slugs" do
33
+ limit = Shipit::Team.columns_hash['slug'].limit
34
+ skip unless limit
35
+
36
+ slug = 'a' * 255
37
+ team = new_team(slug: slug)
38
+
39
+ response = stub(rels: {}, data: [team])
40
+ Shipit.github.api.expects(:org_teams).with('shopify', per_page: 100).returns(response.data)
41
+ Shipit.github.api.expects(:last_response).returns(response)
42
+
43
+ assert_difference -> { Team.count }, 1 do
44
+ Team.find_or_create_by_handle("Shopify/#{slug}")
45
+ end
46
+
47
+ team_record = Team.find_by(name: team.name)
48
+ assert_equal limit, team_record.slug.bytesize
49
+ end
50
+
32
51
  private
33
52
 
34
53
  def members_resource
@@ -46,11 +65,11 @@ module Shipit
46
65
  )
47
66
  end
48
67
 
49
- def new_team
68
+ def new_team(slug: 'new-team')
50
69
  stub(
51
70
  id: 24,
52
71
  name: 'New Team',
53
- slug: 'new-team',
72
+ slug: slug,
54
73
  url: 'https://example.com',
55
74
  description: 'The Best one',
56
75
  organization: 'shopify',
@@ -216,19 +216,24 @@ module Shipit
216
216
  end
217
217
 
218
218
  test "users with legacy encrypted access token get their token reset automatically" do
219
- # See: https://github.com/attr-encrypted/attr_encrypted/blob/53266da546a21afaa1f1b93a461b912f4ccf363b/README.md#upgrading-from-attr_encrypted-v2x-to-v3x
220
219
  legacy = shipit_users(:legacy)
221
- assert_not_nil legacy.encrypted_github_access_token
222
- assert_not_nil legacy.encrypted_github_access_token_iv
223
-
224
220
  assert_nil legacy.github_access_token
225
- legacy.reload
226
- assert_nil legacy.encrypted_github_access_token
227
- assert_nil legacy.encrypted_github_access_token_iv
228
221
 
229
- legacy.update!(github_access_token: 't0k3n')
222
+ legacy.update!(github_access_token: 'ghu_t0k3n')
223
+ assert_equal 'ghu_t0k3n', legacy.github_access_token
224
+ end
225
+
226
+ test "users with legacy encrypted access token can be updated" do
227
+ legacy = shipit_users(:legacy)
228
+ legacy.update!(github_access_token: 'ghu_t0k3n')
230
229
  legacy.reload
231
- assert_equal 't0k3n', legacy.github_access_token
230
+ assert_equal 'ghu_t0k3n', legacy.github_access_token
231
+ end
232
+
233
+ test "users with legacy encrypted access token can have unrelated attributes updated" do
234
+ legacy = shipit_users(:legacy)
235
+ legacy.update!(name: 'Test')
236
+ assert_equal 'Test', legacy.name
232
237
  end
233
238
 
234
239
  test "users are always logged_in?" do
@@ -274,6 +279,21 @@ module Shipit
274
279
  assert_equal user, found_user
275
280
  end
276
281
 
282
+ test "requires_fresh_login? defaults to false" do
283
+ u = User.new
284
+ refute_predicate u, :requires_fresh_login?
285
+ end
286
+
287
+ test "requires_fresh_login? is true for users with legacy github_access_token" do
288
+ @user.update!(github_access_token: 'some_legacy_value')
289
+ assert_predicate @user, :requires_fresh_login?
290
+ end
291
+
292
+ test "requires_fresh_login? is false for users with a new format github_access_token" do
293
+ @user.update!(github_access_token: 'ghu_tok3n')
294
+ refute_predicate @user, :requires_fresh_login?
295
+ end
296
+
277
297
  private
278
298
 
279
299
  def fetch_user
@@ -27,7 +27,7 @@ module Shipit
27
27
 
28
28
  command = @commands.fetch
29
29
 
30
- assert_equal %w(git fetch origin --tags master), command.args
30
+ assert_equal %w(git fetch origin --quiet --tags master), command.args
31
31
  end
32
32
 
33
33
  test "#fetch calls git fetch in git_path directory if repository cache already exist" do
@@ -134,7 +134,11 @@ module Shipit
134
134
 
135
135
  test "#checkout checks out the deployed commit" do
136
136
  command = @commands.checkout(@deploy.until_commit)
137
- assert_equal ['git', '-c', 'advice.detachedHead=false', 'checkout', @deploy.until_commit.sha], command.args
137
+ checkout_args = [
138
+ 'git', '-c', 'advice.detachedHead=false', 'checkout', '--quiet',
139
+ @deploy.until_commit.sha,
140
+ ]
141
+ assert_equal checkout_args, command.args
138
142
  end
139
143
 
140
144
  test "#checkout checks out the deployed commit from the working directory" do