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
|
@@ -4,13 +4,13 @@ module Shipit
|
|
|
4
4
|
|
|
5
5
|
class << self
|
|
6
6
|
def load(payload)
|
|
7
|
-
return
|
|
7
|
+
return if payload.blank?
|
|
8
8
|
json = JSON.parse(payload)
|
|
9
9
|
new(json.delete('id'), json)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def dump(definition)
|
|
13
|
-
return
|
|
13
|
+
return if definition.blank?
|
|
14
14
|
JSON.dump(definition.as_json)
|
|
15
15
|
end
|
|
16
16
|
end
|
|
@@ -9,9 +9,15 @@ module Shipit
|
|
|
9
9
|
|
|
10
10
|
def deploy_state(bypass_safeties = false)
|
|
11
11
|
state = deployable? ? 'allowed' : status.state
|
|
12
|
+
|
|
12
13
|
unless bypass_safeties
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
if blocked?
|
|
15
|
+
state = 'blocked'
|
|
16
|
+
elsif locked?
|
|
17
|
+
state = 'locked'
|
|
18
|
+
elsif stack.active_task?
|
|
19
|
+
state = 'deploying'
|
|
20
|
+
end
|
|
15
21
|
end
|
|
16
22
|
state
|
|
17
23
|
end
|
|
@@ -31,5 +37,10 @@ module Shipit
|
|
|
31
37
|
def deploy_discouraged?
|
|
32
38
|
stack.maximum_commits_per_deploy && index >= stack.maximum_commits_per_deploy
|
|
33
39
|
end
|
|
40
|
+
|
|
41
|
+
def blocked?
|
|
42
|
+
return @blocked if defined?(@blocked)
|
|
43
|
+
@blocked = super
|
|
44
|
+
end
|
|
34
45
|
end
|
|
35
46
|
end
|
data/app/models/shipit/user.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Shipit
|
|
|
7
7
|
has_one :head, serializer: ShortCommitSerializer
|
|
8
8
|
|
|
9
9
|
attributes :id, :number, :title, :github_id, :additions, :deletions, :state, :merge_status, :mergeable,
|
|
10
|
-
:merge_requested_at, :rejection_reason, :html_url
|
|
10
|
+
:merge_requested_at, :rejection_reason, :html_url, :branch, :base_ref
|
|
11
11
|
|
|
12
12
|
def html_url
|
|
13
13
|
github_pull_request_url(object)
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
status_map = {'backlogged' => 'failure', 'locked' => 'failure'}
|
|
3
3
|
xml.instruct!
|
|
4
4
|
xml.Projects do
|
|
5
|
-
xml.Project
|
|
6
|
-
|
|
7
|
-
:
|
|
8
|
-
:
|
|
9
|
-
:
|
|
10
|
-
:
|
|
11
|
-
:
|
|
12
|
-
|
|
5
|
+
xml.Project(
|
|
6
|
+
'',
|
|
7
|
+
name: stack.to_param,
|
|
8
|
+
lastBuildStatus: status_map.fetch(stack.merge_status, stack.merge_status).capitalize,
|
|
9
|
+
activity: deploy.running? ? 'Building' : 'Sleeping',
|
|
10
|
+
lastBuildTime: deploy.ended_at || deploy.started_at || deploy.created_at,
|
|
11
|
+
lastBuildLabel: deploy.id,
|
|
12
|
+
webUrl: stack_url(stack),
|
|
13
|
+
)
|
|
13
14
|
end
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
<% cache deploy.author do %>
|
|
6
6
|
<%= render 'shipit/shared/author', author: deploy.author %>
|
|
7
7
|
<% end %>
|
|
8
|
-
<a href="<%= stack_deploy_path(@stack, deploy) %>" class="status status--<%= deploy.status %>" data-tooltip="<%= deploy.status
|
|
8
|
+
<a href="<%= stack_deploy_path(@stack, deploy) %>" class="status status--<%= deploy.status %>" data-tooltip="<%= deploy_status_in_words(deploy.status) %>">
|
|
9
9
|
<i class="status__icon"></i>
|
|
10
|
-
<span class="visually-hidden"><%= deploy.status %></span>
|
|
10
|
+
<span class="visually-hidden"><%= deploy_status_in_words(deploy.status) %></span>
|
|
11
11
|
</a>
|
|
12
12
|
<div class="commit-details">
|
|
13
13
|
<span class="commit-title">
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
<span class="code-additions">+<%= deploy.additions %></span>
|
|
22
22
|
<span class="code-deletions">-<%= deploy.deletions %></span>
|
|
23
23
|
<% if deploy.ignored_safeties? %><span class="ignored-safeties">ignoring safeties</span><% end %>
|
|
24
|
+
<% if deploy.aborted_by %><span class="aborted-by">aborted by <%= deploy.aborted_by.login %></span><% end %>
|
|
24
25
|
</p>
|
|
25
26
|
<p class="commit-meta">
|
|
26
27
|
<% if read_only %>
|
|
@@ -36,7 +36,10 @@
|
|
|
36
36
|
<div class="banner__content">
|
|
37
37
|
<h2 class="banner__title">
|
|
38
38
|
<i class="icon icon--lock"></i>
|
|
39
|
-
Deploys
|
|
39
|
+
Deploys were locked by <%= stack.lock_author.name %>
|
|
40
|
+
<% unless stack.locked_since.nil? %>
|
|
41
|
+
<%= timeago_tag(stack.locked_since, force: true) %>
|
|
42
|
+
<% end %>
|
|
40
43
|
</h2>
|
|
41
44
|
<p class="banner__text">
|
|
42
45
|
<%= auto_link emojify(stack.lock_reason) %>
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
<%= f.text_field :environment, placeholder: 'production' %>
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
|
+
<div class="field-wrapper">
|
|
17
|
+
<span>Branch: <%= @stack.branch %></span>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
16
20
|
<div class="field-wrapper">
|
|
17
21
|
<%= f.label :deploy_url, 'Deploy URL (Where is this stack deployed to?)' %>
|
|
18
22
|
<%= f.text_field :deploy_url, placeholder: 'https://' %>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<% group.statuses.each do |status| %>
|
|
10
10
|
<div class="status-item status-item--<%= status.state %> <%= :ignored if status.allowed_to_fail? %>">
|
|
11
11
|
<i class="status-item__icon"></i>
|
|
12
|
-
<a href="<%= status.target_url %>" target="_blank">
|
|
12
|
+
<a href="<%= status.target_url %>" <% unless status.target_url.present? %> disabled class="disabled" <% end %> target="_blank">
|
|
13
13
|
<strong class="status-item__service"><%= status.context %></strong>
|
|
14
14
|
</a>
|
|
15
15
|
<span class="status-item__description">— <%= status.description %></span>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<a class="status status--<%= status.state %> <%=
|
|
1
|
+
<a class="status status--<%= status.state %> <%= 'disabled' unless status.target_url.present? %>" <%= 'disabled' unless status.target_url.present? %> <% unless status.group? %>data-tooltip="<%= status.description.presence || status.state.capitalize %>"<% end %> href="<%= status.target_url%>" target="_blank">
|
|
2
2
|
<i class="status__icon"></i>
|
|
3
3
|
<span class="visually-hidden"><%= status.state %></span>
|
|
4
4
|
</a>
|
data/config/locales/en.yml
CHANGED
|
@@ -27,6 +27,7 @@ en:
|
|
|
27
27
|
deploy_button:
|
|
28
28
|
hint:
|
|
29
29
|
max_commits: It is recommended not to deploy more than %{maximum} commits at once.
|
|
30
|
+
blocked: This commit range includes a commit that can't be deployed.
|
|
30
31
|
caption:
|
|
31
32
|
pending: Pending CI
|
|
32
33
|
failure: Failing CI
|
|
@@ -36,6 +37,7 @@ en:
|
|
|
36
37
|
deploying: A Deploy is in Progress
|
|
37
38
|
allowed: Deploy
|
|
38
39
|
missing: Missing CI
|
|
40
|
+
blocked: Blocked
|
|
39
41
|
redeploy_button:
|
|
40
42
|
caption:
|
|
41
43
|
deploying: A Deploy is in Progress
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
host: '
|
|
1
|
+
host: 'https://shipit-engine.myshopify.io'
|
|
2
2
|
redis_url: 'redis://shipit-engine.railgun:6379'
|
|
3
3
|
|
|
4
4
|
github_api:
|
|
@@ -13,10 +13,6 @@ github_oauth:
|
|
|
13
13
|
secret:
|
|
14
14
|
# teams: # Optional
|
|
15
15
|
|
|
16
|
-
# To work on the beta bootstrap re-write
|
|
17
|
-
# features:
|
|
18
|
-
# - bootstrap
|
|
19
|
-
|
|
20
16
|
# To work on the kubernetes deploy script
|
|
21
17
|
# env:
|
|
22
18
|
# KUBECONFIG: # Path of the kubeconfig you want to use.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
class AddBaseInfoToPullRequest < ActiveRecord::Migration[5.1]
|
|
2
|
+
def change
|
|
3
|
+
add_column :pull_requests, :base_ref, :string, limit: 1024
|
|
4
|
+
add_column :pull_requests, :base_commit_id, :integer
|
|
5
|
+
add_foreign_key :pull_requests, :commits, column: :base_commit_id
|
|
6
|
+
end
|
|
7
|
+
end
|
data/lib/shipit/command.rb
CHANGED
|
@@ -8,11 +8,19 @@ module Shipit
|
|
|
8
8
|
MAX_READ = 64.kilobytes
|
|
9
9
|
|
|
10
10
|
Error = Class.new(StandardError)
|
|
11
|
-
Failed = Class.new(Error)
|
|
12
11
|
NotFound = Class.new(Error)
|
|
13
12
|
Denied = Class.new(Error)
|
|
14
13
|
TimedOut = Class.new(Error)
|
|
15
14
|
|
|
15
|
+
class Failed < Error
|
|
16
|
+
attr_reader :exit_code
|
|
17
|
+
|
|
18
|
+
def initialize(message, exit_code)
|
|
19
|
+
super(message)
|
|
20
|
+
@exit_code = exit_code
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
16
24
|
attr_reader :out, :code, :chdir, :env, :args, :pid, :timeout
|
|
17
25
|
|
|
18
26
|
def initialize(*args, default_timeout: Shipit.default_inactivity_timeout, env: {}, chdir:)
|
|
@@ -44,7 +52,7 @@ module Shipit
|
|
|
44
52
|
end
|
|
45
53
|
|
|
46
54
|
def success?
|
|
47
|
-
code
|
|
55
|
+
!code.nil? && code.zero?
|
|
48
56
|
end
|
|
49
57
|
|
|
50
58
|
def exit_message
|
|
@@ -121,7 +129,7 @@ module Shipit
|
|
|
121
129
|
|
|
122
130
|
def stream!(&block)
|
|
123
131
|
stream(&block)
|
|
124
|
-
raise Failed.new(exit_message) unless success?
|
|
132
|
+
raise Failed.new(exit_message, code) unless success?
|
|
125
133
|
self
|
|
126
134
|
end
|
|
127
135
|
|
data/lib/shipit/engine.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'bootstrap'
|
|
2
|
-
|
|
3
1
|
module Shipit
|
|
4
2
|
class Engine < ::Rails::Engine
|
|
5
3
|
isolate_namespace Shipit
|
|
@@ -17,8 +15,6 @@ module Shipit
|
|
|
17
15
|
task.js
|
|
18
16
|
shipit.js
|
|
19
17
|
shipit.css
|
|
20
|
-
shipit_bs.js
|
|
21
|
-
shipit_bs.css
|
|
22
18
|
)
|
|
23
19
|
app.config.assets.precompile << proc do |path|
|
|
24
20
|
path =~ %r{\Aplugins/[\-\w]+\.(js|css)\Z}
|
|
@@ -26,7 +26,7 @@ module Shipit
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def fetch_deployed_revision
|
|
29
|
-
with_temporary_working_directory do |dir|
|
|
29
|
+
with_temporary_working_directory(commit: @stack.commits.last) do |dir|
|
|
30
30
|
spec = DeploySpec::FileSystem.new(dir, @stack.environment)
|
|
31
31
|
outputs = spec.fetch_deployed_revision_steps!.map do |command_line|
|
|
32
32
|
Command.new(command_line, env: env, chdir: dir).run
|
|
@@ -42,6 +42,8 @@ module Shipit
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def with_temporary_working_directory(commit: nil)
|
|
45
|
+
commit ||= @stack.last_deployed_commit.presence || @stack.commits.last
|
|
46
|
+
|
|
45
47
|
@stack.acquire_git_cache_lock do
|
|
46
48
|
if !commit || !fetched?(commit).tap(&:run).success?
|
|
47
49
|
fetch.run!
|
data/lib/shipit/version.rb
CHANGED
data/lib/shipit.rb
CHANGED
|
@@ -30,8 +30,6 @@ require 'faraday-http-cache'
|
|
|
30
30
|
|
|
31
31
|
require 'shipit/version'
|
|
32
32
|
|
|
33
|
-
require 'shipit/template_renderer_extension'
|
|
34
|
-
|
|
35
33
|
require 'shipit/paginator'
|
|
36
34
|
require 'shipit/null_serializer'
|
|
37
35
|
require 'shipit/csv_serializer'
|
|
@@ -56,8 +54,9 @@ module Shipit
|
|
|
56
54
|
|
|
57
55
|
delegate :table_name_prefix, to: :secrets
|
|
58
56
|
|
|
59
|
-
attr_accessor :disable_api_authentication
|
|
60
|
-
|
|
57
|
+
attr_accessor :disable_api_authentication, :timeout_exit_codes
|
|
58
|
+
|
|
59
|
+
self.timeout_exit_codes = [].freeze
|
|
61
60
|
|
|
62
61
|
def app_name
|
|
63
62
|
@app_name ||= secrets.app_name || Rails.application.class.name.split(':').first || 'Shipit'
|
|
@@ -138,6 +137,18 @@ module Shipit
|
|
|
138
137
|
secrets.host.presence
|
|
139
138
|
end
|
|
140
139
|
|
|
140
|
+
def enforce_publish_config
|
|
141
|
+
secrets.enforce_publish_config.presence
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def npm_org_scope
|
|
145
|
+
secrets.npm_org_scope.presence
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def private_npm_registry
|
|
149
|
+
secrets.private_npm_registry.presence
|
|
150
|
+
end
|
|
151
|
+
|
|
141
152
|
def github_teams
|
|
142
153
|
@github_teams ||= github_teams_handles.map { |t| Team.find_or_create_by_handle(t) }
|
|
143
154
|
end
|
|
@@ -195,29 +206,10 @@ module Shipit
|
|
|
195
206
|
end
|
|
196
207
|
end
|
|
197
208
|
|
|
198
|
-
def feature_bootstrap?
|
|
199
|
-
secrets.features.try!(:include?, 'bootstrap')
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
def bootstrap_view_path
|
|
203
|
-
@bootstrap_view_path ||= Engine.root.join('app/views/bootstrap')
|
|
204
|
-
end
|
|
205
|
-
|
|
206
209
|
def default_inactivity_timeout
|
|
207
210
|
secrets.commands_inactivity_timeout || 5.minutes.to_i
|
|
208
211
|
end
|
|
209
212
|
|
|
210
|
-
def automatically_prepend_bundle_exec
|
|
211
|
-
unless defined?(@automatically_prepend_bundle_exec)
|
|
212
|
-
ActiveSupport::Deprecation.warn(
|
|
213
|
-
'Automatically prepending `bundle exec` will be removed in a future version of Shipit, '\
|
|
214
|
-
'set `Shipit.automatically_prepend_bundle_exec = false` to test the new behaviour.',
|
|
215
|
-
)
|
|
216
|
-
@automatically_prepend_bundle_exec = true
|
|
217
|
-
end
|
|
218
|
-
@automatically_prepend_bundle_exec
|
|
219
|
-
end
|
|
220
|
-
|
|
221
213
|
protected
|
|
222
214
|
|
|
223
215
|
def revision_file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
VERSION=$(node --eval "console.log(require('./lerna.json').version);")
|
|
4
|
+
echo -e "\033[0;32mTrying to publish version $VERSION\033[0m"
|
|
5
|
+
|
|
6
|
+
git tag | grep "^v$VERSION$" > /dev/null
|
|
7
|
+
if [ $? != '0' ]; then
|
|
8
|
+
echo -e "\033[1;31mYou need to create the \033[0;33mv$VERSION\033[1;31m tag first.\033[0m"
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
TAG_REV=$(git rev-list -n1 "v$VERSION")
|
|
13
|
+
HEAD_REV=$(git rev-parse HEAD)
|
|
14
|
+
|
|
15
|
+
if [ "$TAG_REV" != "$HEAD_REV" ]; then
|
|
16
|
+
echo -e "\033[1;31mYou're attempting to publish \033[0;33m$HEAD_REV\033[1;31m as \033[0;33mv$VERSION\033[1;31m but it already points to \033[0;33m$TAG_REV\033[1;31m.\033[0m"
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
echo -e "\033[0;32mAll clear!\033[0m"
|
|
21
|
+
exit 0
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
TAGS=$(git tag --points-at HEAD)
|
|
4
|
+
|
|
5
|
+
if [ -z "$TAGS" ]; then
|
|
6
|
+
HEAD_REV=$(git rev-parse HEAD)
|
|
7
|
+
echo -e "\033[1;31mNo tags associated with $HEAD_REV. Did you push your commits and tags?\033[0m"
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
for TAG in $TAGS
|
|
12
|
+
do
|
|
13
|
+
if [[ "${TAG}" == @* ]]; then
|
|
14
|
+
TAG=$(echo "$TAG" | cut -d \/ -f 2)
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
PACKAGE_NAME=$(echo "$TAG" | cut -d \@ -f 1)
|
|
18
|
+
TAG_PACKAGE_VERSION=$(echo "$TAG" | cut -d \@ -f 2)
|
|
19
|
+
ACTUAL_PACKAGE_VERSION=$(node -e "console.log(require('./packages/$PACKAGE_NAME/package.json').version)")
|
|
20
|
+
|
|
21
|
+
if [ "$TAG_PACKAGE_VERSION" != "$ACTUAL_PACKAGE_VERSION" ]; then
|
|
22
|
+
echo -e "\033[1;31m$PACKAGE_NAME is tagged as $TAG_PACKAGE_VERSION, but its package.json version is $ACTUAL_PACKAGE_VERSION.\033[0m"
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
done
|
|
26
|
+
|
|
27
|
+
echo -e "\033[0;32mAll clear!\033[0m"
|
|
28
|
+
exit 0
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const {resolve} = require('path');
|
|
3
|
+
const {existsSync, writeFileSync, readFileSync} = require('fs');
|
|
4
|
+
const npmrc = resolve('.', '.npmrc');
|
|
5
|
+
const npmrcContents = process.argv[2];
|
|
6
|
+
|
|
7
|
+
if (!npmrcContents) {
|
|
8
|
+
console.error('npmrc contents not specified.');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (existsSync(npmrc)) {
|
|
13
|
+
console.log('.npmrc already exists.')
|
|
14
|
+
} else {
|
|
15
|
+
writeFileSync(npmrc, npmrcContents)
|
|
16
|
+
|
|
17
|
+
console.log('\nGenerated .npmrc:');
|
|
18
|
+
console.log(readFileSync(npmrc, {encoding: 'utf8'}))
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
echo -e "\033[1;31m Misconfigured package.json, please ensure the following has been met:\n \033[0m"
|
|
4
|
+
|
|
5
|
+
echo -e "\033[1;31m * Please add a publishConfig with an access setting in your package.json. e.g.,\033[0m"
|
|
6
|
+
echo -e "\n\033[1;31m\t\"publishConfig:\" {\n\t \"access\": \"<public|restricted>\" \n\t} \033[0m"
|
|
7
|
+
echo -e "\n\033[1;31m * If your package is private, ensure your the package name is scoped (@organization/package) \033[0m"
|
|
8
|
+
exit 1
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const {resolve} = require('path');
|
|
3
|
+
const {execSync} = require('child_process')
|
|
4
|
+
const Repository = require(resolve('.', 'node_modules', 'lerna', 'lib', 'Repository'));
|
|
5
|
+
const PackageUtilities = require(resolve('.', 'node_modules', 'lerna', 'lib', 'PackageUtilities'));
|
|
6
|
+
|
|
7
|
+
function npmTag(version) {
|
|
8
|
+
const isNext = ['-beta', '-alpha', '-rc', '-next'].some(distributionType =>
|
|
9
|
+
version.includes(distributionType),
|
|
10
|
+
);
|
|
11
|
+
return isNext ? 'next' : 'latest';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const taggedPackages = execSync('git tag --points-at HEAD')
|
|
15
|
+
.toString()
|
|
16
|
+
.trim()
|
|
17
|
+
.split('\n')
|
|
18
|
+
.map(tag => {
|
|
19
|
+
if (tag.startsWith('@')) {
|
|
20
|
+
return `@${tag.split('@')[1]}`;
|
|
21
|
+
}
|
|
22
|
+
return tag.split('@')[0];
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const repository = new Repository('.');
|
|
26
|
+
const unsortedPackages = PackageUtilities.getPackages({rootPath: '.', packageConfigs: repository.packageConfigs});
|
|
27
|
+
const packages = PackageUtilities.topologicallyBatchPackages(unsortedPackages, true)
|
|
28
|
+
.reduce((acc, packageGroup) => [...acc, ...packageGroup], [])
|
|
29
|
+
.filter(({name}) => taggedPackages.includes(name));
|
|
30
|
+
|
|
31
|
+
packages.forEach(({name, version}) => {
|
|
32
|
+
const command = `node_modules/.bin/lerna publish --yes --npm-client=npm --skip-npm=false --skip-git --force-publish=${name} --repo-version=${version} --scope=${name} --npm-tag=${npmTag(
|
|
33
|
+
version,
|
|
34
|
+
)}`;
|
|
35
|
+
|
|
36
|
+
// eslint-disable-next-line no-console
|
|
37
|
+
console.log(command);
|
|
38
|
+
require('child_process').execSync(command);
|
|
39
|
+
});
|
data/lib/snippets/push-to-heroku
CHANGED
|
@@ -23,17 +23,17 @@ if [[ -z "${HEROKU_APP}" ]]; then
|
|
|
23
23
|
exit 1;
|
|
24
24
|
fi
|
|
25
25
|
|
|
26
|
-
echo "$HEROKU_RELEASES" |
|
|
26
|
+
echo "$HEROKU_RELEASES" | grep 'Current: \(v[0-9]\+\)' >/dev/null
|
|
27
27
|
|
|
28
28
|
if [[ $? -ne 0 ]]; then
|
|
29
29
|
red "Error detecting current heroku release. Message from 'heroku releases':"
|
|
30
30
|
echo "${HEROKU_RELEASES}"
|
|
31
31
|
red "Please contact a heroku collaborator for ${HEROKU_APP}:"
|
|
32
|
-
heroku
|
|
32
|
+
heroku access --app $HEROKU_APP
|
|
33
33
|
exit 1;
|
|
34
34
|
fi
|
|
35
35
|
|
|
36
|
-
HEROKU_LAST_GOOD_RELEASE=`echo "$HEROKU_RELEASES" |
|
|
36
|
+
HEROKU_LAST_GOOD_RELEASE=`echo "$HEROKU_RELEASES" | grep 'Current: \(v[0-9]\+\)' | sed -e 's/.*\(v[0-9]\+\).*/\1/'`
|
|
37
37
|
green "Current heroku release: ${HEROKU_LAST_GOOD_RELEASE}"
|
|
38
38
|
|
|
39
39
|
green "Pushing to heroku."
|
|
@@ -41,7 +41,7 @@ $GIT_COMMAND
|
|
|
41
41
|
if [[ $? -ne 0 ]]; then
|
|
42
42
|
red "Heroku push rejected. See message above."
|
|
43
43
|
red "Please contact a heroku collaborator for ${HEROKU_APP}:"
|
|
44
|
-
heroku
|
|
44
|
+
heroku access --app $HEROKU_APP
|
|
45
45
|
exit 1;
|
|
46
46
|
fi
|
|
47
47
|
|
|
@@ -58,7 +58,7 @@ if [[ "${MIGRATION_STATUS}" != "" ]]; then
|
|
|
58
58
|
if [[ "${POST_MIGRATION_STATUS}" != "" ]]; then
|
|
59
59
|
red "Migration failed! This is bad."
|
|
60
60
|
red "Please contact a heroku collaborator for ${HEROKU_APP}:"
|
|
61
|
-
heroku
|
|
61
|
+
heroku access --app $HEROKU_APP
|
|
62
62
|
red "The app ${HEROKU_APP} will now be reverted to its last working version ${HEROKU_LAST_GOOD_RELEASE}."
|
|
63
63
|
heroku releases:rollback $HEROKU_LAST_GOOD_RELEASE --app $HEROKU_APP
|
|
64
64
|
red "Abort."
|
data/lib/tasks/cron.rake
CHANGED
data/lib/tasks/dev.rake
CHANGED
|
@@ -40,6 +40,13 @@ module Shipit
|
|
|
40
40
|
deploy.user == @user
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
test "#create normalises the claimed user" do
|
|
44
|
+
request.headers['X-Shipit-User'] = @user.login.swapcase
|
|
45
|
+
post :create, params: {stack_id: @stack.to_param, sha: @commit.sha}
|
|
46
|
+
deploy = Deploy.last
|
|
47
|
+
assert_equal deploy.user, @user
|
|
48
|
+
end
|
|
49
|
+
|
|
43
50
|
test "#create renders a 422 if the sha isn't found" do
|
|
44
51
|
post :create, params: {stack_id: @stack.to_param, sha: '123443543545'}
|
|
45
52
|
assert_response :unprocessable_entity
|
|
@@ -52,6 +59,18 @@ module Shipit
|
|
|
52
59
|
assert_json 'errors', 'sha' => ['is too short (minimum is 6 characters)']
|
|
53
60
|
end
|
|
54
61
|
|
|
62
|
+
test "#create renders a 409 if a concurrent task is already running" do
|
|
63
|
+
assert_difference -> { @stack.deploys.count }, 1 do
|
|
64
|
+
post :create, params: {stack_id: @stack.to_param, sha: @commit.sha}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
assert_no_difference -> { @stack.deploys.count } do
|
|
68
|
+
post :create, params: {stack_id: @stack.to_param, sha: @commit.sha}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
assert_response :conflict
|
|
72
|
+
end
|
|
73
|
+
|
|
55
74
|
test "#create refuses to deploy locked stacks" do
|
|
56
75
|
@stack.update!(lock_reason: 'Something broken')
|
|
57
76
|
|
|
@@ -149,6 +149,11 @@ module Shipit
|
|
|
149
149
|
assert_redirected_to stack_settings_path(@stack)
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
+
test "#sync_webhooks displays a flash message" do
|
|
153
|
+
post :sync_webhooks, params: {id: @stack.to_param}
|
|
154
|
+
assert_equal 'Webhooks syncing scheduled', flash[:success]
|
|
155
|
+
end
|
|
156
|
+
|
|
152
157
|
test "#clear_git_cache queues a ClearGitCacheJob" do
|
|
153
158
|
assert_enqueued_with(job: ClearGitCacheJob, args: [@stack]) do
|
|
154
159
|
post :clear_git_cache, params: {id: @stack.to_param}
|
|
@@ -156,6 +161,11 @@ module Shipit
|
|
|
156
161
|
assert_redirected_to stack_settings_path(@stack)
|
|
157
162
|
end
|
|
158
163
|
|
|
164
|
+
test "#clear_git_cache displays a flash message" do
|
|
165
|
+
post :clear_git_cache, params: {id: @stack.to_param}
|
|
166
|
+
assert_equal 'Git Cache clearing scheduled', flash[:success]
|
|
167
|
+
end
|
|
168
|
+
|
|
159
169
|
test "#update redirects to return_to parameter" do
|
|
160
170
|
patch :update, params: {id: @stack.to_param, stack: {ignore_ci: false}, return_to: stack_path(@stack)}
|
|
161
171
|
assert_redirected_to stack_path(@stack)
|