shipit-engine 0.8.9 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/shipit_bs.js.coffee +2 -0
- data/app/assets/javascripts/task.js.coffee +14 -5
- data/app/assets/javascripts/task/search_bar.js.coffee +52 -0
- data/app/assets/javascripts/task/stream.js.coffee +9 -2
- data/app/assets/javascripts/task/tty.js.coffee +75 -28
- data/app/assets/stylesheets/_base/_forms.scss +5 -0
- data/app/assets/stylesheets/_pages/_commits.scss +1 -1
- data/app/assets/stylesheets/_pages/_deploy.scss +56 -24
- data/app/assets/stylesheets/_pages/_settings.scss +5 -0
- data/app/assets/stylesheets/_structure/_layout.scss +1 -0
- data/app/assets/stylesheets/_structure/_main.scss +4 -0
- data/app/assets/stylesheets/shipit.scss +2 -0
- data/app/assets/stylesheets/shipit_bs.scss +22 -0
- data/app/controllers/shipit/deploys_controller.rb +5 -1
- data/app/controllers/shipit/shipit_controller.rb +10 -3
- data/app/controllers/shipit/stacks_controller.rb +12 -3
- data/app/controllers/shipit/tasks_controller.rb +4 -0
- data/app/helpers/shipit/shipit_helper.rb +18 -0
- data/app/helpers/shipit/stacks_helper.rb +1 -1
- data/app/jobs/shipit/cache_deploy_spec_job.rb +2 -0
- data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -0
- data/app/jobs/shipit/git_mirror_update_job.rb +2 -0
- data/app/jobs/shipit/perform_task_job.rb +1 -0
- data/app/models/shipit/commit.rb +2 -2
- data/app/models/shipit/deploy.rb +1 -1
- data/app/models/shipit/deploy_spec/bundler_discovery.rb +1 -1
- data/app/models/shipit/duration.rb +28 -0
- data/app/models/shipit/stack.rb +33 -11
- data/app/models/shipit/task.rb +26 -3
- data/app/serializers/shipit/task_serializer.rb +14 -1
- data/app/views/bootstrap/shipit/missing_settings.html.erb +97 -0
- data/app/views/bootstrap/shipit/stacks/new.html.erb +44 -0
- data/app/views/layouts/shipit.html.erb +1 -1
- data/app/views/layouts/shipit_bootstrap.html.erb +44 -0
- data/app/views/shipit/commits/_commit.html.erb +3 -2
- data/app/views/shipit/deploys/_deploy.html.erb +11 -2
- data/app/views/shipit/deploys/show.html.erb +1 -1
- data/app/views/shipit/stacks/new.html.erb +12 -12
- data/app/views/shipit/stacks/settings.html.erb +5 -0
- data/app/views/shipit/stacks/show.html.erb +1 -1
- data/app/views/shipit/tasks/_task.html.erb +10 -2
- data/app/views/shipit/tasks/_task_output.html.erb +11 -1
- data/app/views/shipit/tasks/show.html.erb +1 -1
- data/config/routes.rb +1 -0
- data/db/migrate/20160324155046_add_started_at_and_ended_at_on_tasks.rb +25 -0
- data/lib/shipit.rb +13 -0
- data/lib/shipit/command.rb +13 -9
- data/lib/shipit/engine.rb +8 -0
- data/lib/shipit/template_renderer_extension.rb +16 -0
- data/lib/shipit/version.rb +1 -1
- data/test/controllers/deploys_controller_test.rb +11 -0
- data/test/controllers/stacks_controller_test.rb +5 -0
- data/test/controllers/tasks_controller_test.rb +6 -0
- data/test/dummy/config/secrets.example.yml +4 -0
- data/test/dummy/config/secrets.yml +2 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/bar.txt +2 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/dkfdsf +0 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/dskjfsd +0 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/dslkjfjsdf +0 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/plopfizz +0 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/sd +0 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/sdkfjsdf +1 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/sdlfjsdfdsfj +0 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/sdlkfjsdlkfjsdlkfjdsfsdfksdfjsldkfjsdlkfjsdf +0 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/shipit.yml +32 -0
- data/test/dummy/data/stacks/byroot/junk/production/deploys/83/toto.txt +2 -0
- data/test/dummy/data/stacks/byroot/junk/production/git/bar.txt +1 -0
- data/test/dummy/data/stacks/byroot/junk/production/git/shipit.yml +6 -1
- data/test/dummy/data/stacks/byroot/test/production/git/README.md +1 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +3 -1
- data/test/dummy/db/seeds.rb +6 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/db/test.sqlite3-journal +0 -0
- data/test/fixtures/shipit/tasks.yml +11 -0
- data/test/models/commits_test.rb +1 -1
- data/test/models/deploys_test.rb +40 -0
- data/test/models/duration_test.rb +13 -0
- data/test/models/stacks_test.rb +3 -4
- data/test/unit/command_test.rb +14 -0
- data/vendor/assets/javascripts/clusterize.js +327 -0
- data/vendor/assets/javascripts/mousetrap-global-bind.js +43 -0
- data/vendor/assets/javascripts/mousetrap.js +1021 -0
- data/vendor/assets/javascripts/string_includes.js +14 -0
- data/vendor/assets/stylesheets/clusterize.css +27 -0
- metadata +100 -3
- data/app/assets/javascripts/task/sticky_element.js.coffee +0 -16
@@ -0,0 +1,22 @@
|
|
1
|
+
// Custom bootstrap variables must be set or import before bootstrap itself.
|
2
|
+
@import "bootstrap";
|
3
|
+
|
4
|
+
body {
|
5
|
+
padding-top: 5rem;
|
6
|
+
}
|
7
|
+
|
8
|
+
.navbar-brand {
|
9
|
+
background: asset-data-url('anchor.svg') center center no-repeat;
|
10
|
+
display: block;
|
11
|
+
width: 40px;
|
12
|
+
height: 40px;
|
13
|
+
transition: transform .3s ease-in-out;
|
14
|
+
text-indent: -9999px;
|
15
|
+
top: 50%;
|
16
|
+
right: 100%;
|
17
|
+
margin-right: 1em;
|
18
|
+
|
19
|
+
&:hover {
|
20
|
+
transform: rotate(-25deg);
|
21
|
+
}
|
22
|
+
}
|
@@ -9,10 +9,14 @@ module Shipit
|
|
9
9
|
def new
|
10
10
|
@commit = @stack.commits.by_sha!(params[:sha])
|
11
11
|
@commit.checks.schedule if @stack.checks?
|
12
|
-
@deploy = @stack.
|
12
|
+
@deploy = @stack.build_deploy(@commit, current_user)
|
13
13
|
end
|
14
14
|
|
15
15
|
def show
|
16
|
+
respond_to do |format|
|
17
|
+
format.html
|
18
|
+
format.text { render plain: @deploy.chunk_output }
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
def create
|
@@ -11,9 +11,12 @@ module Shipit
|
|
11
11
|
helper Shipit::Engine.routes.url_helpers
|
12
12
|
include Shipit::Engine.routes.url_helpers
|
13
13
|
|
14
|
-
before_action
|
15
|
-
|
16
|
-
|
14
|
+
before_action(
|
15
|
+
:toogle_bootstrap_feature,
|
16
|
+
:ensure_required_settings,
|
17
|
+
:force_github_authentication,
|
18
|
+
:set_variant,
|
19
|
+
)
|
17
20
|
|
18
21
|
# Respond to HTML by default
|
19
22
|
respond_to :html
|
@@ -24,6 +27,10 @@ module Shipit
|
|
24
27
|
|
25
28
|
private
|
26
29
|
|
30
|
+
def toogle_bootstrap_feature
|
31
|
+
prepend_view_path(Shipit.bootstrap_view_path) if Shipit.feature_bootstrap?
|
32
|
+
end
|
33
|
+
|
27
34
|
def ensure_required_settings
|
28
35
|
return if Shipit.all_settings_present?
|
29
36
|
|
@@ -24,8 +24,16 @@ module Shipit
|
|
24
24
|
@commits = @commits.to_a
|
25
25
|
end
|
26
26
|
|
27
|
+
def lookup
|
28
|
+
@stack = Stack.find(params[:id])
|
29
|
+
redirect_to stack_url(@stack)
|
30
|
+
end
|
31
|
+
|
27
32
|
def create
|
28
|
-
@stack = Stack.
|
33
|
+
@stack = Stack.new(create_params)
|
34
|
+
unless @stack.save
|
35
|
+
flash[:warning] = @stack.errors.full_messages.to_sentence
|
36
|
+
end
|
29
37
|
respond_with(@stack)
|
30
38
|
end
|
31
39
|
|
@@ -41,7 +49,7 @@ module Shipit
|
|
41
49
|
RefreshStatusesJob.perform_later(stack_id: @stack.id)
|
42
50
|
GithubSyncJob.perform_later(stack_id: @stack.id)
|
43
51
|
flash[:success] = 'Refresh scheduled'
|
44
|
-
redirect_to :back
|
52
|
+
redirect_to request.referer ? :back : stack_path(@stack)
|
45
53
|
end
|
46
54
|
|
47
55
|
def update
|
@@ -73,7 +81,8 @@ module Shipit
|
|
73
81
|
end
|
74
82
|
|
75
83
|
def update_params
|
76
|
-
params.require(:stack).permit(:deploy_url, :lock_reason, :
|
84
|
+
params.require(:stack).permit(:deploy_url, :lock_reason, :environment,
|
85
|
+
:continuous_deployment, :ignore_ci).tap do |params|
|
77
86
|
params[:lock_author_id] = params[:lock_reason].present? ? current_user.id : nil
|
78
87
|
end
|
79
88
|
end
|
@@ -1,5 +1,23 @@
|
|
1
1
|
module Shipit
|
2
2
|
module ShipitHelper
|
3
|
+
def emojify(content)
|
4
|
+
h(content).to_str.gsub(/:([\w+-]+):/) do |match|
|
5
|
+
if emoji = Emoji.find_by_alias($1)
|
6
|
+
%(
|
7
|
+
<img
|
8
|
+
alt="##{$1}"
|
9
|
+
src="#{image_path("emoji/#{emoji.image_filename}")}"
|
10
|
+
style="vertical-align:middle"
|
11
|
+
width="20"
|
12
|
+
height="20"
|
13
|
+
/>
|
14
|
+
)
|
15
|
+
else
|
16
|
+
match
|
17
|
+
end
|
18
|
+
end.html_safe if content.present?
|
19
|
+
end
|
20
|
+
|
3
21
|
def include_plugins(stack)
|
4
22
|
stack.plugins.flat_map do |plugin, config|
|
5
23
|
plugin_tags(plugin, config)
|
@@ -37,7 +37,7 @@ module Shipit
|
|
37
37
|
|
38
38
|
def render_commit_message(commit)
|
39
39
|
message = commit.pull_request_title || commit.message
|
40
|
-
content_tag(:span, message.truncate(COMMIT_TITLE_LENGTH), class: 'event-message')
|
40
|
+
content_tag(:span, emojify(message.truncate(COMMIT_TITLE_LENGTH)), class: 'event-message')
|
41
41
|
end
|
42
42
|
|
43
43
|
def render_commit_message_with_link(commit)
|
@@ -3,6 +3,8 @@ module Shipit
|
|
3
3
|
include BackgroundJob::Unique
|
4
4
|
|
5
5
|
def perform(stack)
|
6
|
+
return if stack.inaccessible?
|
7
|
+
|
6
8
|
commands = Commands.for(stack)
|
7
9
|
commands.with_temporary_working_directory(commit: stack.commits.last) do |path|
|
8
10
|
stack.update!(cached_deploy_spec: DeploySpec::FileSystem.new(path, stack.environment))
|
data/app/models/shipit/commit.rb
CHANGED
@@ -23,12 +23,12 @@ module Shipit
|
|
23
23
|
|
24
24
|
def self.newer_than(commit)
|
25
25
|
return all unless commit
|
26
|
-
where('id > ?', commit.
|
26
|
+
where('id > ?', commit.try(:id) || commit)
|
27
27
|
end
|
28
28
|
|
29
29
|
def self.until(commit)
|
30
30
|
return all unless commit
|
31
|
-
where('id <= ?', commit.
|
31
|
+
where('id <= ?', commit.try(:id) || commit)
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.successful
|
data/app/models/shipit/deploy.rb
CHANGED
@@ -26,7 +26,7 @@ module Shipit
|
|
26
26
|
# Heroku apps often specify a ruby version.
|
27
27
|
if /darwin/ =~ RUBY_PLATFORM
|
28
28
|
# OSX is nitpicky about the -i.
|
29
|
-
%q(sed -i '' '/^ruby\s/d' Gemfile)
|
29
|
+
%q(/usr/bin/sed -i '' '/^ruby\s/d' Gemfile)
|
30
30
|
else
|
31
31
|
%q(sed -i '/^ruby\s/d' Gemfile)
|
32
32
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Shipit
|
2
|
+
class Duration
|
3
|
+
UNITS = {
|
4
|
+
's' => :seconds,
|
5
|
+
'm' => :minutes,
|
6
|
+
'h' => :hours,
|
7
|
+
'd' => :days,
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
def initialize(seconds)
|
11
|
+
@seconds = seconds
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_i
|
15
|
+
@seconds.to_i
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
seconds = to_i
|
20
|
+
days, seconds = seconds.divmod(1.day.to_i)
|
21
|
+
if days > 0
|
22
|
+
"#{days}d#{Time.at(seconds).utc.strftime('%Hh%Mm%Ss')}"
|
23
|
+
else
|
24
|
+
Time.at(seconds).utc.strftime('%Hh%Mm%Ss')[/[^0a-z]\w+/] || '0s'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/app/models/shipit/stack.rb
CHANGED
@@ -2,6 +2,22 @@ require 'fileutils'
|
|
2
2
|
|
3
3
|
module Shipit
|
4
4
|
class Stack < ActiveRecord::Base
|
5
|
+
module NoDeployedCommit
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def id
|
9
|
+
-1
|
10
|
+
end
|
11
|
+
|
12
|
+
def sha
|
13
|
+
''
|
14
|
+
end
|
15
|
+
|
16
|
+
def blank?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
5
21
|
REPO_OWNER_MAX_SIZE = 39
|
6
22
|
REPO_NAME_MAX_SIZE = 100
|
7
23
|
ENVIRONMENT_MAX_SIZE = 50
|
@@ -36,7 +52,8 @@ module Shipit
|
|
36
52
|
after_commit :setup_hooks, :sync_github, on: :create
|
37
53
|
after_touch :clear_cache
|
38
54
|
|
39
|
-
validates :repo_name, uniqueness: {scope: %i(repo_owner environment)
|
55
|
+
validates :repo_name, uniqueness: {scope: %i(repo_owner environment),
|
56
|
+
message: 'cannot be used more than once with this environment'}
|
40
57
|
validates :repo_owner, :repo_name, :environment, presence: true, ascii_only: true
|
41
58
|
validates :repo_owner, format: {with: /\A[a-z0-9_\-\.]+\z/}, length: {maximum: REPO_OWNER_MAX_SIZE}
|
42
59
|
validates :repo_name, format: {with: /\A[a-z0-9_\-\.]+\z/}, length: {maximum: REPO_NAME_MAX_SIZE}
|
@@ -57,7 +74,7 @@ module Shipit
|
|
57
74
|
end
|
58
75
|
|
59
76
|
def trigger_task(definition_id, user, env: nil)
|
60
|
-
commit = last_deployed_commit
|
77
|
+
commit = last_deployed_commit.presence || commits.first
|
61
78
|
task = tasks.create(
|
62
79
|
user_id: user.id,
|
63
80
|
definition: find_task_definition(definition_id),
|
@@ -69,15 +86,19 @@ module Shipit
|
|
69
86
|
task
|
70
87
|
end
|
71
88
|
|
72
|
-
def
|
73
|
-
since_commit = last_deployed_commit
|
74
|
-
|
75
|
-
deploy = deploys.create(
|
89
|
+
def build_deploy(until_commit, user, env: nil)
|
90
|
+
since_commit = last_deployed_commit.presence || commits.first
|
91
|
+
deploys.build(
|
76
92
|
user_id: user.id,
|
77
93
|
until_commit: until_commit,
|
78
94
|
since_commit: since_commit,
|
79
95
|
env: filter_deploy_envs(env || {}),
|
80
96
|
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def trigger_deploy(*args)
|
100
|
+
deploy = build_deploy(*args)
|
101
|
+
deploy.save!
|
81
102
|
deploy.enqueue
|
82
103
|
deploy
|
83
104
|
end
|
@@ -95,10 +116,11 @@ module Shipit
|
|
95
116
|
end
|
96
117
|
|
97
118
|
def update_deployed_revision(sha)
|
98
|
-
return if active_task?
|
99
|
-
|
100
119
|
last_deploy = deploys_and_rollbacks.last
|
101
|
-
|
120
|
+
return if last_deploy.try!(:active?)
|
121
|
+
|
122
|
+
actual_deployed_commit = commits.reachable.by_sha(sha)
|
123
|
+
return unless actual_deployed_commit
|
102
124
|
|
103
125
|
if last_deploy && actual_deployed_commit == last_deploy.until_commit
|
104
126
|
last_deploy.accept!
|
@@ -107,7 +129,7 @@ module Shipit
|
|
107
129
|
else
|
108
130
|
deploys.create!(
|
109
131
|
until_commit: actual_deployed_commit,
|
110
|
-
since_commit: last_deployed_commit,
|
132
|
+
since_commit: last_deployed_commit.presence || commits.first,
|
111
133
|
status: 'success',
|
112
134
|
)
|
113
135
|
end
|
@@ -144,7 +166,7 @@ module Shipit
|
|
144
166
|
if deploy = last_successful_deploy
|
145
167
|
deploy.until_commit
|
146
168
|
else
|
147
|
-
|
169
|
+
NoDeployedCommit
|
148
170
|
end
|
149
171
|
end
|
150
172
|
|
data/app/models/shipit/task.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Shipit
|
2
2
|
class Task < ActiveRecord::Base
|
3
|
+
ACTIVE_STATUSES = %w(pending running aborting).freeze
|
4
|
+
COMPLETED_STATUSES = %w(success error failed flapping aborted).freeze
|
5
|
+
|
3
6
|
belongs_to :deploy, foreign_key: :parent_id, required: false # required for fixtures
|
4
7
|
|
5
8
|
belongs_to :user
|
@@ -13,8 +16,8 @@ module Shipit
|
|
13
16
|
serialize :env, Hash
|
14
17
|
|
15
18
|
scope :success, -> { where(status: 'success') }
|
16
|
-
scope :completed, -> { where(status:
|
17
|
-
scope :active, -> { where(status:
|
19
|
+
scope :completed, -> { where(status: COMPLETED_STATUSES) }
|
20
|
+
scope :active, -> { where(status: ACTIVE_STATUSES) }
|
18
21
|
scope :exclusive, -> { where(allow_concurrency: false) }
|
19
22
|
|
20
23
|
scope :due_for_rollup, -> { completed.where(rolled_up: false).where('created_at <= ?', 1.hour.ago) }
|
@@ -23,6 +26,14 @@ module Shipit
|
|
23
26
|
after_commit :emit_hooks
|
24
27
|
|
25
28
|
state_machine :status, initial: :pending do
|
29
|
+
before_transition any => :running do |task|
|
30
|
+
task.started_at ||= Time.now.utc
|
31
|
+
end
|
32
|
+
|
33
|
+
before_transition any => %i(success failed error) do |task|
|
34
|
+
task.ended_at ||= Time.now.utc
|
35
|
+
end
|
36
|
+
|
26
37
|
after_transition any => %i(success failed error) do |task|
|
27
38
|
task.async_refresh_deployed_revision
|
28
39
|
end
|
@@ -69,6 +80,10 @@ module Shipit
|
|
69
80
|
state :flapping
|
70
81
|
end
|
71
82
|
|
83
|
+
def active?
|
84
|
+
status.in?(ACTIVE_STATUSES)
|
85
|
+
end
|
86
|
+
|
72
87
|
def report_failure!(_error)
|
73
88
|
reload
|
74
89
|
if aborting?
|
@@ -79,7 +94,7 @@ module Shipit
|
|
79
94
|
end
|
80
95
|
|
81
96
|
def report_error!(error)
|
82
|
-
write("#{error.class}: #{error.message}\n\t#{error.backtrace.join("\t")}\n")
|
97
|
+
write("#{error.class}: #{error.message}\n\t#{error.backtrace.join("\n\t")}\n")
|
83
98
|
error!
|
84
99
|
end
|
85
100
|
|
@@ -87,6 +102,14 @@ module Shipit
|
|
87
102
|
|
88
103
|
delegate :checklist, to: :definition
|
89
104
|
|
105
|
+
def duration?
|
106
|
+
started_at? && ended_at?
|
107
|
+
end
|
108
|
+
|
109
|
+
def duration
|
110
|
+
Duration.new(ended_at - started_at) if duration?
|
111
|
+
end
|
112
|
+
|
90
113
|
def spec
|
91
114
|
@spec ||= DeploySpec::FileSystem.new(working_directory, stack.environment)
|
92
115
|
end
|
@@ -5,7 +5,20 @@ module Shipit
|
|
5
5
|
has_one :author
|
6
6
|
has_one :revision, serializer: ShortCommitSerializer
|
7
7
|
|
8
|
-
attributes
|
8
|
+
attributes(*%i(
|
9
|
+
id
|
10
|
+
url
|
11
|
+
html_url
|
12
|
+
output_url
|
13
|
+
type
|
14
|
+
status
|
15
|
+
action
|
16
|
+
description
|
17
|
+
started_at
|
18
|
+
ended_at
|
19
|
+
updated_at
|
20
|
+
created_at
|
21
|
+
))
|
9
22
|
|
10
23
|
def revision
|
11
24
|
object.until_commit
|