shipit-engine 0.20.0 → 0.21.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.
- checksums.yaml +5 -5
- data/README.md +43 -6
- data/app/assets/stylesheets/_base/_base.scss +4 -0
- data/app/assets/stylesheets/_pages/_commits.scss +3 -1
- data/app/assets/stylesheets/_pages/_deploy.scss +4 -2
- data/app/controllers/concerns/shipit/authentication.rb +1 -1
- data/app/controllers/shipit/api/base_controller.rb +6 -1
- data/app/controllers/shipit/api/pull_requests_controller.rb +1 -1
- data/app/controllers/shipit/commit_checks_controller.rb +1 -1
- data/app/controllers/shipit/shipit_controller.rb +1 -5
- data/app/controllers/shipit/stacks_controller.rb +2 -0
- data/app/controllers/shipit/tasks_controller.rb +1 -1
- data/app/controllers/shipit/webhooks_controller.rb +2 -2
- data/app/helpers/shipit/deploys_helper.rb +9 -0
- data/app/helpers/shipit/shipit_helper.rb +17 -15
- data/app/helpers/shipit/stacks_helper.rb +6 -1
- data/app/jobs/shipit/destroy_stack_job.rb +4 -2
- data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -1
- data/app/jobs/shipit/github_sync_job.rb +1 -1
- data/app/jobs/shipit/merge_pull_requests_job.rb +3 -3
- data/app/jobs/shipit/perform_task_job.rb +3 -0
- data/app/jobs/shipit/purge_old_deliveries_job.rb +1 -0
- data/app/models/shipit/api_client.rb +1 -1
- data/app/models/shipit/commit.rb +29 -6
- data/app/models/shipit/commit_deployment.rb +1 -1
- data/app/models/shipit/commit_deployment_status.rb +1 -1
- data/app/models/shipit/deploy_spec/bundler_discovery.rb +1 -10
- data/app/models/shipit/deploy_spec/file_system.rb +6 -0
- data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +1 -1
- data/app/models/shipit/deploy_spec/lerna_discovery.rb +85 -0
- data/app/models/shipit/deploy_spec/npm_discovery.rb +103 -5
- data/app/models/shipit/deploy_spec/pypi_discovery.rb +4 -2
- data/app/models/shipit/deploy_spec/rubygems_discovery.rb +4 -2
- data/app/models/shipit/deploy_spec.rb +19 -2
- data/app/models/shipit/duration.rb +1 -1
- data/app/models/shipit/github_status.rb +1 -1
- data/app/models/shipit/hook.rb +4 -5
- data/app/models/shipit/output_chunk.rb +1 -1
- data/app/models/shipit/pull_request.rb +37 -16
- data/app/models/shipit/stack.rb +17 -11
- data/app/models/shipit/status/common.rb +4 -0
- data/app/models/shipit/status/group.rb +4 -0
- data/app/models/shipit/task.rb +20 -8
- data/app/models/shipit/task_definition.rb +2 -2
- data/app/models/shipit/undeployed_commit.rb +13 -2
- data/app/models/shipit/user.rb +1 -1
- data/app/serializers/shipit/pull_request_serializer.rb +1 -1
- data/app/serializers/shipit/tail_task_serializer.rb +1 -1
- data/app/views/shipit/ccmenu/project.xml.builder +9 -8
- data/app/views/shipit/deploys/_deploy.html.erb +3 -2
- data/app/views/shipit/stacks/_banners.html.erb +4 -1
- data/app/views/shipit/stacks/settings.html.erb +4 -0
- data/app/views/shipit/statuses/_group.html.erb +1 -1
- data/app/views/shipit/statuses/_status.html.erb +1 -1
- data/app/views/shipit/tasks/_task.html.erb +1 -2
- data/config/locales/en.yml +2 -0
- data/config/secrets.development.example.yml +0 -4
- data/config/secrets.development.shopify.yml +1 -5
- data/db/migrate/20170904103242_reindex_deliveries.rb +7 -0
- data/db/migrate/20171120161420_add_base_info_to_pull_request.rb +7 -0
- data/db/migrate/20180202220850_add_aborted_by_to_tasks.rb +5 -0
- data/lib/shipit/command.rb +11 -3
- data/lib/shipit/engine.rb +0 -4
- data/lib/shipit/stack_commands.rb +3 -1
- data/lib/shipit/version.rb +1 -1
- data/lib/shipit.rb +15 -23
- data/lib/snippets/assert-lerna-fixed-version-tag +21 -0
- data/lib/snippets/assert-lerna-independent-version-tags +28 -0
- data/lib/snippets/generate-local-npmrc +19 -0
- data/lib/snippets/misconfigured-npm-publish-config +8 -0
- data/lib/snippets/publish-lerna-independent-packages +39 -0
- data/lib/snippets/push-to-heroku +5 -5
- data/lib/tasks/cron.rake +1 -1
- data/lib/tasks/dev.rake +1 -1
- data/test/controllers/api/deploys_controller_test.rb +19 -0
- data/test/controllers/api/stacks_controller_test.rb +1 -1
- data/test/controllers/github_authentication_controller_test.rb +1 -1
- data/test/controllers/stacks_controller_test.rb +10 -0
- data/test/controllers/tasks_controller_test.rb +2 -0
- data/test/controllers/webhooks_controller_test.rb +0 -7
- data/test/dummy/config/secrets.yml +0 -2
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +5 -3
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/fixtures/shipit/commits.yml +53 -0
- data/test/fixtures/shipit/pull_requests.yml +52 -0
- data/test/fixtures/shipit/stacks.yml +35 -0
- data/test/fixtures/shipit/statuses.yml +27 -0
- data/test/fixtures/shipit/tasks.yml +14 -0
- data/test/helpers/queries_helper.rb +1 -1
- data/test/jobs/merge_pull_requests_job_test.rb +19 -2
- data/test/jobs/perform_task_job_test.rb +26 -2
- data/test/models/commits_test.rb +55 -6
- data/test/models/deploy_spec_test.rb +288 -52
- data/test/models/deploys_test.rb +7 -7
- data/test/models/hook_test.rb +7 -1
- data/test/models/pull_request_test.rb +78 -24
- data/test/models/stacks_test.rb +23 -19
- data/test/models/status/group_test.rb +6 -0
- data/test/models/undeployed_commits_test.rb +9 -0
- data/test/models/users_test.rb +2 -2
- data/test/test_helper.rb +1 -1
- metadata +211 -224
- data/app/assets/javascripts/shipit_bs.js.coffee +0 -2
- data/app/assets/stylesheets/shipit_bs.scss +0 -22
- data/app/views/bootstrap/shipit/missing_settings.html.erb +0 -97
- data/app/views/bootstrap/shipit/stacks/new.html.erb +0 -44
- data/app/views/layouts/shipit_bootstrap.html.erb +0 -44
- data/lib/shipit/template_renderer_extension.rb +0 -16
- data/test/dummy/db/test.sqlite3-journal +0 -0
|
@@ -284,11 +284,16 @@ module Shipit
|
|
|
284
284
|
'require' => [],
|
|
285
285
|
'ignore' => [],
|
|
286
286
|
'revalidate_after' => nil,
|
|
287
|
+
'max_divergence' => {
|
|
288
|
+
'commits' => nil,
|
|
289
|
+
'age' => nil,
|
|
290
|
+
},
|
|
287
291
|
},
|
|
288
292
|
'ci' => {
|
|
289
293
|
'hide' => [],
|
|
290
294
|
'allow_failures' => [],
|
|
291
295
|
'require' => [],
|
|
296
|
+
'blocking' => [],
|
|
292
297
|
},
|
|
293
298
|
'machine' => {'environment' => {}, 'directory' => nil, 'cleanup' => true},
|
|
294
299
|
'review' => {'checklist' => [], 'monitoring' => [], 'checks' => []},
|
|
@@ -318,59 +323,19 @@ module Shipit
|
|
|
318
323
|
assert_equal 'SAFETY_DISABLED', variable_definition.name
|
|
319
324
|
end
|
|
320
325
|
|
|
321
|
-
test "task definitions prepend bundle exec by default" do
|
|
322
|
-
@spec.expects(:load_config).returns('tasks' => {'restart' => {'steps' => %w(foo)}})
|
|
323
|
-
@spec.expects(:bundler?).returns(true).at_least_once
|
|
324
|
-
assert_deprecated(/Automatically prepending `bundle exec`/) do
|
|
325
|
-
definition = @spec.find_task_definition('restart')
|
|
326
|
-
assert_equal ['bundle exec foo'], definition.steps
|
|
327
|
-
end
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
test "task definitions prepend bundle exec if enabled" do
|
|
331
|
-
Shipit.expects(:automatically_prepend_bundle_exec).returns(true).at_least_once
|
|
326
|
+
test "task definitions don't prepend bundle exec by default" do
|
|
332
327
|
@spec.expects(:load_config).returns('tasks' => {'restart' => {'steps' => %w(foo)}})
|
|
333
|
-
@spec.expects(:bundler?).returns(true).at_least_once
|
|
334
328
|
definition = @spec.find_task_definition('restart')
|
|
335
|
-
|
|
336
|
-
assert_equal ['bundle exec foo'], definition.steps
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
test "task definitions do not prepend bundle exec if disabled" do
|
|
340
|
-
Shipit.expects(:automatically_prepend_bundle_exec).returns(false).at_least_once
|
|
341
|
-
@spec.expects(:load_config).returns('tasks' => {'restart' => {'steps' => %w(foo)}})
|
|
342
|
-
definition = @spec.find_task_definition('restart')
|
|
343
|
-
|
|
344
329
|
assert_equal ['foo'], definition.steps
|
|
345
330
|
end
|
|
346
331
|
|
|
347
|
-
test "task definitions
|
|
348
|
-
Shipit.expects(:automatically_prepend_bundle_exec).returns(true).at_least_once
|
|
349
|
-
@spec.expects(:load_config).returns('tasks' => {'restart' => {'steps' => ['bundle exec foo']}})
|
|
350
|
-
@spec.stubs(:bundler?).returns(true)
|
|
351
|
-
definition = @spec.find_task_definition('restart')
|
|
352
|
-
|
|
353
|
-
assert_equal ['bundle exec foo'], definition.steps
|
|
354
|
-
end
|
|
355
|
-
|
|
356
|
-
test "task definitions do not prepend bundle exec if depedency step is overridden" do
|
|
357
|
-
@spec.expects(:load_config).returns(
|
|
358
|
-
'dependencies' => {'override' => []},
|
|
359
|
-
'tasks' => {'restart' => {'steps' => %w(foo)}},
|
|
360
|
-
)
|
|
361
|
-
@spec.expects(:bundler?).returns(true).at_least_once
|
|
362
|
-
definition = @spec.find_task_definition('restart')
|
|
363
|
-
|
|
364
|
-
assert_equal ['foo'], definition.steps
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
test "task definitions prepend bundle exec before serialization" do
|
|
332
|
+
test "task definitions don't bundle exec before serialization" do
|
|
368
333
|
@spec.expects(:discover_task_definitions).returns('restart' => {'steps' => %w(foo)})
|
|
369
334
|
@spec.expects(:bundler?).returns(true).at_least_once
|
|
370
335
|
|
|
371
336
|
cached_spec = DeploySpec.load(DeploySpec.dump(@spec))
|
|
372
337
|
definition = cached_spec.find_task_definition('restart')
|
|
373
|
-
assert_equal ['
|
|
338
|
+
assert_equal ['foo'], definition.steps
|
|
374
339
|
end
|
|
375
340
|
|
|
376
341
|
test "#task_definitions returns kubernetes commands as well as comands from the config" do
|
|
@@ -455,6 +420,16 @@ module Shipit
|
|
|
455
420
|
assert_equal %w(ci/circleci ci/jenkins), @spec.hidden_statuses
|
|
456
421
|
end
|
|
457
422
|
|
|
423
|
+
test "#required_statuses automatically includes #blocking_statuses" do
|
|
424
|
+
@spec.expects(:load_config).returns(
|
|
425
|
+
'ci' => {
|
|
426
|
+
'require' => %w(ci/circleci),
|
|
427
|
+
'blocking' => %w(soc/compliance),
|
|
428
|
+
},
|
|
429
|
+
)
|
|
430
|
+
assert_equal %w(ci/circleci soc/compliance), @spec.required_statuses
|
|
431
|
+
end
|
|
432
|
+
|
|
458
433
|
test "pull_request_ignored_statuses defaults to the union of ci.hide and ci.allow_failures" do
|
|
459
434
|
@spec.expects(:load_config).returns(
|
|
460
435
|
'ci' => {
|
|
@@ -573,26 +548,43 @@ module Shipit
|
|
|
573
548
|
assert_equal ['fake gem task'], @spec.deploy_steps
|
|
574
549
|
end
|
|
575
550
|
|
|
551
|
+
test 'lerna monorepos take priority over solo npm deploys' do
|
|
552
|
+
@spec.expects(:discover_npm_package).never
|
|
553
|
+
@spec.stubs(:discover_lerna_packages).returns(['fake monorepo task']).once
|
|
554
|
+
|
|
555
|
+
assert_equal ['fake monorepo task'], @spec.deploy_steps
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
test '#lerna? is false if there is no lerna.json' do
|
|
559
|
+
@spec.expects(:lerna_json).returns(Shipit::Engine.root.join("tmp-#{SecureRandom.hex}"))
|
|
560
|
+
refute @spec.lerna?
|
|
561
|
+
end
|
|
562
|
+
|
|
576
563
|
test '#npm? is false if there is no package.json' do
|
|
577
564
|
@spec.expects(:package_json).returns(Shipit::Engine.root.join("tmp-#{SecureRandom.hex}"))
|
|
578
565
|
refute @spec.npm?
|
|
579
566
|
end
|
|
580
567
|
|
|
581
|
-
test '#npm? is
|
|
568
|
+
test '#npm? is true if npm package is public' do
|
|
582
569
|
file = Pathname.new('/tmp/fake_package.json')
|
|
583
|
-
file.write('{"private":
|
|
570
|
+
file.write('{"private": false}')
|
|
584
571
|
|
|
585
572
|
@spec.expects(:package_json).returns(file)
|
|
586
|
-
|
|
573
|
+
|
|
574
|
+
assert @spec.npm?
|
|
587
575
|
end
|
|
588
576
|
|
|
589
|
-
test '#npm? is
|
|
577
|
+
test '#npm? is false if npm package is private' do
|
|
590
578
|
file = Pathname.new('/tmp/fake_package.json')
|
|
591
|
-
file.write('{"private":
|
|
579
|
+
file.write('{"private": true}')
|
|
592
580
|
|
|
593
581
|
@spec.expects(:package_json).returns(file)
|
|
582
|
+
refute @spec.npm?
|
|
583
|
+
end
|
|
594
584
|
|
|
595
|
-
|
|
585
|
+
test 'lerna monorepos have a checklist' do
|
|
586
|
+
@spec.stubs(:lerna?).returns(true).at_least_once
|
|
587
|
+
assert_match(/lerna publish --skip-npm/, @spec.review_checklist[0])
|
|
596
588
|
end
|
|
597
589
|
|
|
598
590
|
test 'npm packages have a checklist' do
|
|
@@ -600,14 +592,223 @@ module Shipit
|
|
|
600
592
|
assert_match(/npm version/, @spec.review_checklist[0])
|
|
601
593
|
end
|
|
602
594
|
|
|
595
|
+
test '#lerna_version returns the monorepo root version number' do
|
|
596
|
+
file = Pathname.new('/tmp/fake_lerna.json')
|
|
597
|
+
file.write('{"version": "1.0.0-beta.1"}')
|
|
598
|
+
|
|
599
|
+
@spec.expects(:lerna_json).returns(file)
|
|
600
|
+
assert_equal '1.0.0-beta.1', @spec.lerna_version
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
test '#package_version returns the version number' do
|
|
604
|
+
file = Pathname.new('/tmp/fake_package.json')
|
|
605
|
+
file.write('{"version": "1.0.0-beta.1"}')
|
|
606
|
+
|
|
607
|
+
@spec.expects(:package_json).returns(file)
|
|
608
|
+
assert_equal '1.0.0-beta.1', @spec.package_version
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
test '#dist_tag returns "latest" if the version does not contains a standard pre-release tag' do
|
|
612
|
+
assert_equal 'latest', @spec.dist_tag('1.0.0')
|
|
613
|
+
assert_equal 'latest', @spec.dist_tag('1.0.0-shopifyv4')
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
test '#dist_tag returns "next" if the version contains a pre-release tag' do
|
|
617
|
+
assert_equal 'next', @spec.dist_tag('1.0.0-alpha.1')
|
|
618
|
+
assert_equal 'next', @spec.dist_tag('1.0.0-beta')
|
|
619
|
+
assert_equal 'next', @spec.dist_tag('1.0.0-rc.3')
|
|
620
|
+
assert_equal 'next', @spec.dist_tag('1.0.0-next')
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
test '#dependencies_steps returns lerna setup if a `lerna.json` is present' do
|
|
624
|
+
@spec.expects(:lerna?).returns(true).at_least_once
|
|
625
|
+
assert_equal ['npm install --no-progress', 'node_modules/.bin/lerna bootstrap'], @spec.dependencies_steps
|
|
626
|
+
end
|
|
627
|
+
|
|
603
628
|
test '#dependencies_steps returns `npm install` if a `package.json` is present' do
|
|
604
629
|
@spec.expects(:npm?).returns(true).at_least_once
|
|
605
630
|
assert_equal ['npm install --no-progress'], @spec.dependencies_steps
|
|
606
631
|
end
|
|
607
632
|
|
|
633
|
+
test '#publish_lerna_packages checks if independent version tags exist, and then invokes lerna deploy script' do
|
|
634
|
+
@spec.stubs(:lerna?).returns(true)
|
|
635
|
+
@spec.stubs(:lerna_version).returns('independent')
|
|
636
|
+
assert_equal 'assert-lerna-independent-version-tags', @spec.deploy_steps[0]
|
|
637
|
+
assert_equal 'publish-lerna-independent-packages', @spec.deploy_steps[1]
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
test '#publish_lerna_packages checks if fixed version tag exists, and then invokes lerna deploy script' do
|
|
641
|
+
@spec.stubs(:lerna?).returns(true)
|
|
642
|
+
@spec.stubs(:lerna_version).returns('1.0.0')
|
|
643
|
+
assert_equal 'assert-lerna-fixed-version-tag', @spec.deploy_steps[0]
|
|
644
|
+
assert_equal 'node_modules/.bin/lerna publish --yes --skip-git --repo-version 1.0.0 --force-publish=* --npm-tag latest', @spec.deploy_steps[1]
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
test '#enforce_publish_config? is false when Shipit.enforce_publish_config is nil' do
|
|
648
|
+
Shipit.stubs(:enforce_publish_config).returns(nil)
|
|
649
|
+
refute @spec.enforce_publish_config?
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
test '#enforce_publish_config? is false when Shipit.enforce_publish_config is 0' do
|
|
653
|
+
Shipit.stubs(:enforce_publish_config).returns('0')
|
|
654
|
+
refute @spec.enforce_publish_config?
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
test '#enforce_publish_config? is true when Shipit.enforce_publish_config is 1' do
|
|
658
|
+
Shipit.stubs(:enforce_publish_config).returns('1')
|
|
659
|
+
assert @spec.enforce_publish_config?
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
test '#valid_publish_config? is false when enforce_publish_config? is true and publishConfig is missing from package.json' do
|
|
663
|
+
Shipit.stubs(:private_npm_registry).returns('some_private_registry')
|
|
664
|
+
@spec.stubs(:enforce_publish_config?).returns(true)
|
|
665
|
+
@spec.stubs(:publish_config_access).returns('restricted')
|
|
666
|
+
|
|
667
|
+
package_json = Pathname.new('/tmp/fake_package.json')
|
|
668
|
+
package_json.write('{"name": "foo"}')
|
|
669
|
+
|
|
670
|
+
@spec.expects(:package_json).returns(package_json)
|
|
671
|
+
refute @spec.valid_publish_config?
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
test '#valid_publish_config? is true when enforce_publish_config? is true and publishConfig.access is public' do
|
|
675
|
+
Shipit.stubs(:private_npm_registry).returns('some_private_registry')
|
|
676
|
+
@spec.stubs(:enforce_publish_config?).returns(true)
|
|
677
|
+
@spec.stubs(:publish_config_access).returns('public')
|
|
678
|
+
@spec.stubs(:publish_config).returns('something')
|
|
679
|
+
|
|
680
|
+
assert @spec.valid_publish_config?
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
test '#valid_publish_config? is true when shipit does not enforce a publishConfig' do
|
|
684
|
+
@spec.stubs(:lerna_version).returns('1.0.0')
|
|
685
|
+
assert @spec.valid_publish_config?
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
test '#publish_config returns publishConfig from package.json' do
|
|
689
|
+
package_json = Pathname.new('/tmp/fake_package.json')
|
|
690
|
+
package_json.write('{"publishConfig": "foo"}')
|
|
691
|
+
|
|
692
|
+
@spec.expects(:package_json).returns(package_json)
|
|
693
|
+
assert_equal "foo", @spec.publish_config
|
|
694
|
+
end
|
|
695
|
+
|
|
696
|
+
test '#valid_publish_config_access? is false when publishConfig.access is invalid' do
|
|
697
|
+
@spec.stubs(:publish_config_access).returns('foo')
|
|
698
|
+
refute @spec.valid_publish_config_access?
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
test '#valid_publish_config_access? is true when publishConfig.access is public or restricted' do
|
|
702
|
+
@spec.stubs(:publish_config_access).returns('public')
|
|
703
|
+
assert @spec.valid_publish_config_access?
|
|
704
|
+
|
|
705
|
+
@spec.stubs(:publish_config_access).returns('restricted')
|
|
706
|
+
assert @spec.valid_publish_config_access?
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
test '#publish_config_access is restricted when enforce_publish_config? is true and publishConfig is missing' do
|
|
710
|
+
package_json = Pathname.new('/tmp/fake_package.json')
|
|
711
|
+
package_json.write('{"name": "@shopify/foo"}')
|
|
712
|
+
|
|
713
|
+
@spec.stubs(:enforce_publish_config?).returns(true)
|
|
714
|
+
@spec.expects(:package_json).returns(package_json)
|
|
715
|
+
assert_equal 'restricted', @spec.publish_config_access
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
test '#publish_config_access is public when enforce_publish_config? is false and publishConfig is missing' do
|
|
719
|
+
package_json = Pathname.new('/tmp/fake_package.json')
|
|
720
|
+
package_json.write('{"name": "@shopify/foo"}')
|
|
721
|
+
|
|
722
|
+
@spec.stubs(:enforce_publish_config?).returns(false)
|
|
723
|
+
@spec.expects(:package_json).returns(package_json)
|
|
724
|
+
assert_equal 'public', @spec.publish_config_access
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
test '#publish_config_access returns publishConfig.access from package.json when enforce_publish_config? is true' do
|
|
728
|
+
package_json = Pathname.new('/tmp/fake_package.json')
|
|
729
|
+
package_json.write('{
|
|
730
|
+
"name": "@shopify/foo",
|
|
731
|
+
"publishConfig": {
|
|
732
|
+
"access": "foo"
|
|
733
|
+
}
|
|
734
|
+
}')
|
|
735
|
+
|
|
736
|
+
@spec.stubs(:enforce_publish_config?).returns(false)
|
|
737
|
+
@spec.expects(:package_json).returns(package_json)
|
|
738
|
+
assert_equal 'foo', @spec.publish_config_access
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
test "#scoped_package? is false when Shipit.npm_org_scope is not set and the package is private" do
|
|
742
|
+
Shipit.stubs(:npm_org_scope).returns(nil)
|
|
743
|
+
@spec.stubs(:publish_config_access).returns('restricted')
|
|
744
|
+
refute @spec.scoped_package?
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
test "#scoped_package? is true when Shipit.npm_org_scope is set and package_name starts with scope and the package is private" do
|
|
748
|
+
Shipit.stubs(:npm_org_scope).returns('@shopify')
|
|
749
|
+
@spec.stubs(:publish_config_access).returns('restricted')
|
|
750
|
+
@spec.stubs(:package_name).returns('@shopify/polaris')
|
|
751
|
+
assert @spec.scoped_package?
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
test "#private_scoped_package? is false when private packages are not scoped" do
|
|
755
|
+
@spec.stubs(:scoped_package?).returns(false)
|
|
756
|
+
@spec.stubs(:publish_config_access).returns("restricted")
|
|
757
|
+
refute @spec.private_scoped_package?
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
test "#private_scoped_package? is true when private packages are scoped" do
|
|
761
|
+
@spec.stubs(:scoped_package?).returns(true)
|
|
762
|
+
@spec.stubs(:publish_config_access).returns("restricted")
|
|
763
|
+
assert @spec.private_scoped_package?
|
|
764
|
+
end
|
|
765
|
+
|
|
608
766
|
test '#publish_npm_package checks if version tag exists, and then invokes npm deploy script' do
|
|
609
767
|
@spec.stubs(:npm?).returns(true)
|
|
610
|
-
|
|
768
|
+
@spec.stubs(:package_version).returns('1.0.0')
|
|
769
|
+
@spec.stubs(:valid_publish_config?).returns(true)
|
|
770
|
+
@spec.stubs(:publish_config_access).returns('restricted')
|
|
771
|
+
@spec.stubs(:registry).returns("@private:registry=some_private_registry")
|
|
772
|
+
assert_equal ['assert-npm-version-tag', 'npm publish --tag latest --access restricted'], @spec.deploy_steps
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
test '#npmrc_contents returns a scoped private package configuration when the package is scoped and private' do
|
|
776
|
+
registry = "@shopify:registry=some_private_registry"
|
|
777
|
+
Shipit.stubs(:npm_org_scope).returns('@shopify')
|
|
778
|
+
Shipit.stubs(:private_npm_registry).returns('some_private_registry')
|
|
779
|
+
@spec.stubs(:scoped_package?).returns(true)
|
|
780
|
+
@spec.stubs(:publish_config_access).returns('restricted')
|
|
781
|
+
assert_equal registry, @spec.registry
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
test '#npmrc_contents returns a public scoped package configuration when the package is scoped and public' do
|
|
785
|
+
registry = "@shopify:registry=https://registry.npmjs.org/"
|
|
786
|
+
Shipit.stubs(:npm_org_scope).returns('@shopify')
|
|
787
|
+
@spec.stubs(:scoped_package?).returns(true)
|
|
788
|
+
@spec.stubs(:publish_config_access).returns('public')
|
|
789
|
+
assert_equal registry, @spec.registry
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
test '#npmrc_contents returns a public non-scoped package configuration when the package is not scoped and public' do
|
|
793
|
+
registry = "registry=https://registry.npmjs.org/"
|
|
794
|
+
@spec.stubs(:scoped_package?).returns(false)
|
|
795
|
+
@spec.stubs(:publish_config_access).returns('public')
|
|
796
|
+
assert_equal registry, @spec.registry
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
test '#publish_lerna_packages guesses npm tag' do
|
|
800
|
+
@spec.stubs(:lerna?).returns(true)
|
|
801
|
+
@spec.stubs(:lerna_version).returns('1.0.0-alpha.1')
|
|
802
|
+
assert_match(/--npm-tag next/, @spec.deploy_steps.last)
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
test '#publish_npm_package checks if version tag and a pre-release flag exist, and then invokes npm deploy script' do
|
|
806
|
+
@spec.stubs(:npm?).returns(true)
|
|
807
|
+
@spec.stubs(:package_version).returns('1.0.0-alpha.1')
|
|
808
|
+
@spec.stubs(:valid_publish_config?).returns(true)
|
|
809
|
+
@spec.stubs(:publish_config_access).returns('restricted')
|
|
810
|
+
@spec.stubs(:registry).returns("@private:registry=some_private_registry")
|
|
811
|
+
assert_equal ['assert-npm-version-tag', 'npm publish --tag next --access restricted'], @spec.deploy_steps
|
|
611
812
|
end
|
|
612
813
|
|
|
613
814
|
test 'bundler installs take priority over yarn installs' do
|
|
@@ -663,14 +864,49 @@ module Shipit
|
|
|
663
864
|
assert_equal ['yarn install --no-progress'], @spec.dependencies_steps
|
|
664
865
|
end
|
|
665
866
|
|
|
666
|
-
test '#
|
|
867
|
+
test '#publish_npm_package checks if version tag exists, and then invokes npm publish script' do
|
|
667
868
|
@spec.stubs(:yarn?).returns(true).at_least_once
|
|
668
|
-
|
|
869
|
+
@spec.stubs(:package_version).returns('1.0.0')
|
|
870
|
+
@spec.stubs(:valid_publish_config?).returns(true)
|
|
871
|
+
@spec.stubs(:publish_config_access).returns('restricted')
|
|
872
|
+
@spec.stubs(:registry).returns("@private:registry=some_private_registry")
|
|
873
|
+
assert_equal ['assert-npm-version-tag', 'npm publish --tag latest --access restricted'], @spec.deploy_steps
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
test '#publish_npm_package checks if version tag exists, generates npmrc, and then invokes npm publish script when enforce_publish_config? is true' do
|
|
877
|
+
@spec.stubs(:yarn?).returns(true).at_least_once
|
|
878
|
+
@spec.stubs(:package_version).returns('1.0.0')
|
|
879
|
+
@spec.stubs(:valid_publish_config?).returns(true)
|
|
880
|
+
|
|
881
|
+
@spec.stubs(:publish_config_access).returns('restricted')
|
|
882
|
+
@spec.stubs(:enforce_publish_config?).returns(true)
|
|
883
|
+
@spec.stubs(:registry).returns('fake')
|
|
884
|
+
|
|
885
|
+
generate_npmrc = 'generate-local-npmrc "fake"'
|
|
886
|
+
npm_publish = 'npm publish --tag latest --access restricted'
|
|
887
|
+
deploy_steps = ['assert-npm-version-tag', generate_npmrc, npm_publish]
|
|
888
|
+
assert_equal deploy_steps, @spec.deploy_steps
|
|
669
889
|
end
|
|
670
890
|
|
|
671
891
|
test 'yarn checklist takes precedence over npm checklist' do
|
|
672
892
|
@spec.stubs(:yarn?).returns(true).at_least_once
|
|
673
893
|
assert_match(/yarn version/, @spec.review_checklist[0])
|
|
674
894
|
end
|
|
895
|
+
|
|
896
|
+
test "max_divergence_commits defaults to `nil" do
|
|
897
|
+
@spec.expects(:load_config).returns({})
|
|
898
|
+
assert_nil @spec.max_divergence_commits
|
|
899
|
+
end
|
|
900
|
+
|
|
901
|
+
test "max_divergence_age defaults to `nil` if `merge.max_divergence.age` cannot be parsed" do
|
|
902
|
+
@spec.expects(:load_config).returns(
|
|
903
|
+
'merge' => {
|
|
904
|
+
'max_divergence' => {
|
|
905
|
+
'age' => 'badbadbad',
|
|
906
|
+
},
|
|
907
|
+
},
|
|
908
|
+
)
|
|
909
|
+
assert_nil @spec.max_divergence_age
|
|
910
|
+
end
|
|
675
911
|
end
|
|
676
912
|
end
|
data/test/models/deploys_test.rb
CHANGED
|
@@ -229,7 +229,7 @@ module Shipit
|
|
|
229
229
|
@deploy = shipit_deploys(:shipit_running)
|
|
230
230
|
@deploy.complete!
|
|
231
231
|
@stack.reload
|
|
232
|
-
assert_in_delta @deploy.ended_at, @stack.last_deployed_at,
|
|
232
|
+
assert_in_delta @deploy.ended_at, @stack.last_deployed_at, 2
|
|
233
233
|
end
|
|
234
234
|
|
|
235
235
|
test "transitioning to success schedule a MergePullRequests job" do
|
|
@@ -264,7 +264,7 @@ module Shipit
|
|
|
264
264
|
@deploy = shipit_deploys(:shipit_running)
|
|
265
265
|
@deploy.ping
|
|
266
266
|
@deploy.pid = 42
|
|
267
|
-
@deploy.abort!(rollback_once_aborted: true)
|
|
267
|
+
@deploy.abort!(rollback_once_aborted: true, aborted_by: @user)
|
|
268
268
|
|
|
269
269
|
assert_difference -> { @stack.rollbacks.count }, 1 do
|
|
270
270
|
assert_enqueued_with(job: PerformTaskJob) do
|
|
@@ -346,12 +346,12 @@ module Shipit
|
|
|
346
346
|
|
|
347
347
|
test "abort! transition to `aborting`" do
|
|
348
348
|
@deploy.ping
|
|
349
|
-
@deploy.abort!
|
|
349
|
+
@deploy.abort!(aborted_by: @user)
|
|
350
350
|
assert_equal 'aborting', @deploy.status
|
|
351
351
|
end
|
|
352
352
|
|
|
353
353
|
test "abort! schedule the rollback if `rollback_once_aborted` is true" do
|
|
354
|
-
@deploy.abort!(rollback_once_aborted: true)
|
|
354
|
+
@deploy.abort!(rollback_once_aborted: true, aborted_by: @user)
|
|
355
355
|
assert_predicate @deploy.reload, :rollback_once_aborted?
|
|
356
356
|
end
|
|
357
357
|
|
|
@@ -359,11 +359,11 @@ module Shipit
|
|
|
359
359
|
@deploy.ping
|
|
360
360
|
aborts = []
|
|
361
361
|
|
|
362
|
-
@deploy.abort!
|
|
362
|
+
@deploy.abort!(aborted_by: @user)
|
|
363
363
|
@deploy.should_abort? { |abort_count| aborts << abort_count }
|
|
364
364
|
assert_equal [1], aborts
|
|
365
365
|
|
|
366
|
-
3.times { @deploy.abort! }
|
|
366
|
+
3.times { @deploy.abort!(aborted_by: @user) }
|
|
367
367
|
@deploy.should_abort? { |abort_count| aborts << abort_count }
|
|
368
368
|
assert_equal [1, 2, 3, 4], aborts
|
|
369
369
|
end
|
|
@@ -373,7 +373,7 @@ module Shipit
|
|
|
373
373
|
refute_predicate @deploy, :alive?
|
|
374
374
|
refute_predicate @deploy, :finished?
|
|
375
375
|
|
|
376
|
-
@deploy.abort!
|
|
376
|
+
@deploy.abort!(aborted_by: @user)
|
|
377
377
|
assert_predicate @deploy, :error?
|
|
378
378
|
end
|
|
379
379
|
|
data/test/models/hook_test.rb
CHANGED
|
@@ -58,10 +58,16 @@ module Shipit
|
|
|
58
58
|
|
|
59
59
|
test "#purge_old_deliveries!" do
|
|
60
60
|
Hook.deliver(:deploy, @stack, 'foo' => 42)
|
|
61
|
+
@hook.deliveries.update_all(status: 'sent')
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
previous_ids = @hook.deliveries.sent.order(id: :desc).pluck(:id)
|
|
64
|
+
|
|
65
|
+
assert_difference -> { @hook.deliveries.sent.count }, -1 do
|
|
63
66
|
@hook.purge_old_deliveries!(keep: 1)
|
|
64
67
|
end
|
|
68
|
+
|
|
69
|
+
after_ids = @hook.deliveries.sent.order(id: :desc).pluck(:id)
|
|
70
|
+
assert_equal previous_ids[0..-2], after_ids
|
|
65
71
|
end
|
|
66
72
|
end
|
|
67
73
|
end
|
|
@@ -29,7 +29,7 @@ module Shipit
|
|
|
29
29
|
PullRequest.request_merge!(@stack, @pr.number, @user)
|
|
30
30
|
assert_predicate @pr.reload, :pending?
|
|
31
31
|
assert_not_equal original_merge_requested_at, @pr.merge_requested_at
|
|
32
|
-
assert_in_delta Time.now.utc, @pr.merge_requested_at,
|
|
32
|
+
assert_in_delta Time.now.utc, @pr.merge_requested_at, 2
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
test ".request_merge! retry rejected pull requests" do
|
|
@@ -39,7 +39,7 @@ module Shipit
|
|
|
39
39
|
PullRequest.request_merge!(@stack, @pr.number, @user)
|
|
40
40
|
assert_predicate @pr.reload, :pending?
|
|
41
41
|
assert_not_equal original_merge_requested_at, @pr.merge_requested_at
|
|
42
|
-
assert_in_delta Time.now.utc, @pr.merge_requested_at,
|
|
42
|
+
assert_in_delta Time.now.utc, @pr.merge_requested_at, 2
|
|
43
43
|
assert_nil @pr.rejection_reason
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -68,6 +68,7 @@ module Shipit
|
|
|
68
68
|
pull_request = shipit_pull_requests(:shipit_fetching)
|
|
69
69
|
|
|
70
70
|
head_sha = '64b3833d39def7ec65b57b42f496eb27ab4980b6'
|
|
71
|
+
base_sha = 'ba7ab50e02286f7d6c60c1ef75258133dd9ea763'
|
|
71
72
|
Shipit.github_api.expects(:pull_request).with(@stack.github_repo_name, pull_request.number).returns(
|
|
72
73
|
stub(
|
|
73
74
|
id: 4_857_578,
|
|
@@ -82,6 +83,10 @@ module Shipit
|
|
|
82
83
|
ref: 'super-branch',
|
|
83
84
|
sha: head_sha,
|
|
84
85
|
),
|
|
86
|
+
base: stub(
|
|
87
|
+
ref: 'default-branch',
|
|
88
|
+
sha: base_sha,
|
|
89
|
+
),
|
|
85
90
|
),
|
|
86
91
|
)
|
|
87
92
|
|
|
@@ -91,22 +96,25 @@ module Shipit
|
|
|
91
96
|
name: 'Bob the Builder',
|
|
92
97
|
email: 'bob@bob.com',
|
|
93
98
|
)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
99
|
+
|
|
100
|
+
[head_sha, base_sha].each do |sha|
|
|
101
|
+
Shipit.github_api.expects(:commit).with(@stack.github_repo_name, sha).returns(
|
|
102
|
+
stub(
|
|
103
|
+
sha: sha,
|
|
104
|
+
author: author,
|
|
105
|
+
committer: author,
|
|
106
|
+
commit: stub(
|
|
107
|
+
message: 'Great feature',
|
|
108
|
+
author: stub(date: 1.day.ago),
|
|
109
|
+
committer: stub(date: 1.day.ago),
|
|
110
|
+
),
|
|
111
|
+
stats: stub(
|
|
112
|
+
additions: 24,
|
|
113
|
+
deletions: 5,
|
|
114
|
+
),
|
|
107
115
|
),
|
|
108
|
-
)
|
|
109
|
-
|
|
116
|
+
)
|
|
117
|
+
end
|
|
110
118
|
|
|
111
119
|
Shipit.github_api.expects(:statuses).with(@stack.github_repo_name, head_sha).returns([stub(
|
|
112
120
|
state: 'success',
|
|
@@ -156,21 +164,30 @@ module Shipit
|
|
|
156
164
|
assert_equal 'merge_conflict', @pr.rejection_reason
|
|
157
165
|
end
|
|
158
166
|
|
|
159
|
-
test "#reject_unless_mergeable! rejects the PR if it has a failing
|
|
160
|
-
@pr.head.statuses.create!(stack: @pr.stack, state: '
|
|
167
|
+
test "#reject_unless_mergeable! rejects the PR if it has a failing CI status" do
|
|
168
|
+
@pr.head.statuses.create!(stack: @pr.stack, state: 'failure', context: 'ci/circle')
|
|
161
169
|
|
|
162
170
|
refute_predicate @pr, :all_status_checks_passed?
|
|
171
|
+
assert_predicate @pr, :any_status_checks_failed?
|
|
163
172
|
assert_equal true, @pr.reject_unless_mergeable!
|
|
164
173
|
assert_predicate @pr, :rejected?
|
|
165
174
|
assert_equal 'ci_failing', @pr.rejection_reason
|
|
166
175
|
end
|
|
167
176
|
|
|
168
|
-
test "#
|
|
169
|
-
@pr.
|
|
177
|
+
test "#reject_unless_mergeable! does not reject the PR if it has a pending CI status" do
|
|
178
|
+
@pr.head.statuses.create!(stack: @pr.stack, state: 'pending', context: 'ci/circle')
|
|
170
179
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
180
|
+
refute_predicate @pr, :all_status_checks_passed?
|
|
181
|
+
refute_predicate @pr, :any_status_checks_failed?
|
|
182
|
+
assert_equal false, @pr.reject_unless_mergeable!
|
|
183
|
+
refute_predicate @pr, :rejected?
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
test "#reject_unless_mergeable! rejects the PR if it is stale" do
|
|
187
|
+
@pr.stubs(:stale?).returns(true)
|
|
188
|
+
assert_equal true, @pr.reject_unless_mergeable!
|
|
189
|
+
assert_predicate @pr, :rejected?
|
|
190
|
+
assert_equal 'requires_rebase', @pr.rejection_reason
|
|
174
191
|
end
|
|
175
192
|
|
|
176
193
|
test "#merge! raises a PullRequest::NotReady if the PR isn't mergeable yet" do
|
|
@@ -211,5 +228,42 @@ module Shipit
|
|
|
211
228
|
@stack.reload
|
|
212
229
|
end
|
|
213
230
|
end
|
|
231
|
+
|
|
232
|
+
test "#all_status_checks_passed? returns false when head commit is unknown" do
|
|
233
|
+
@pr.update(head_id: nil)
|
|
234
|
+
refute_predicate @pr, :all_status_checks_passed?
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
test "#stale? returns false by default" do
|
|
238
|
+
refute_predicate @pr, :stale?
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
test "#stale? returns true when the branch falls behind the maximum commits" do
|
|
242
|
+
@pr.base_commit = shipit_commits(:second)
|
|
243
|
+
@pr.base_ref = 'default-branch'
|
|
244
|
+
Shipit.github_api.expects(:compare).with(@stack.github_repo_name, @pr.base_ref, @pr.head.sha).returns(
|
|
245
|
+
stub(
|
|
246
|
+
behind_by: 10,
|
|
247
|
+
),
|
|
248
|
+
)
|
|
249
|
+
spec = {'merge' => {'max_divergence' => {'commits' => 1}}}
|
|
250
|
+
@pr.stack.cached_deploy_spec = DeploySpec.new(spec)
|
|
251
|
+
assert_predicate @pr, :stale?
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
test "#stale? returns true when the branch falls behind the maximum age" do
|
|
255
|
+
@pr.base_commit = shipit_commits(:second)
|
|
256
|
+
@pr.head.committed_at = 2.hours.ago
|
|
257
|
+
spec = {'merge' => {'max_divergence' => {'age' => '1h'}}}
|
|
258
|
+
@pr.stack.cached_deploy_spec = DeploySpec.new(spec)
|
|
259
|
+
assert_predicate @pr, :stale?
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
test "#stale? is false when base_commit information is missing" do
|
|
263
|
+
@pr.base_commit = nil
|
|
264
|
+
spec = {'merge' => {'max_divergence' => {'age' => '1h', 'commits' => 10}}}
|
|
265
|
+
@pr.stack.cached_deploy_spec = DeploySpec.new(spec)
|
|
266
|
+
refute_predicate @pr, :stale?
|
|
267
|
+
end
|
|
214
268
|
end
|
|
215
269
|
end
|