shipit-engine 0.16.0 → 0.17.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/app/assets/images/caret-down.svg +1 -0
  4. data/app/assets/javascripts/shipit/stacks.js.coffee +10 -0
  5. data/app/assets/stylesheets/_base/_banner.scss +7 -3
  6. data/app/assets/stylesheets/_base/_base.scss +0 -74
  7. data/app/assets/stylesheets/_base/_buttons.scss +7 -3
  8. data/app/assets/stylesheets/_base/_colors.scss +2 -0
  9. data/app/assets/stylesheets/_base/_icons.scss +8 -0
  10. data/app/assets/stylesheets/_base/_spacing.scss +21 -0
  11. data/app/assets/stylesheets/_pages/_commits.scss +41 -3
  12. data/app/assets/stylesheets/_structure/_layout.scss +8 -35
  13. data/app/assets/stylesheets/_structure/_main.scss +2 -2
  14. data/app/assets/stylesheets/_structure/_navigation.scss +89 -0
  15. data/app/assets/stylesheets/shipit.scss +3 -0
  16. data/app/controllers/concerns/shipit/api/rendering.rb +3 -6
  17. data/app/controllers/shipit/api/ccmenu_controller.rb +4 -0
  18. data/app/controllers/shipit/commits_controller.rb +18 -0
  19. data/app/jobs/shipit/destroy_stack_job.rb +25 -0
  20. data/app/jobs/shipit/github_sync_job.rb +12 -1
  21. data/app/jobs/shipit/merge_pull_requests_job.rb +3 -0
  22. data/app/models/shipit/commit.rb +14 -2
  23. data/app/models/shipit/deploy.rb +5 -0
  24. data/app/models/shipit/deploy_spec.rb +9 -6
  25. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +24 -2
  26. data/app/models/shipit/pull_request.rb +16 -1
  27. data/app/models/shipit/stack.rb +11 -4
  28. data/app/models/shipit/task_definition.rb +4 -0
  29. data/app/models/shipit/team.rb +1 -1
  30. data/app/models/shipit/undeployed_commit.rb +1 -2
  31. data/app/models/shipit/user.rb +1 -1
  32. data/app/models/shipit/variable_definition.rb +5 -0
  33. data/app/serializers/shipit/stack_serializer.rb +1 -1
  34. data/app/views/layouts/shipit.html.erb +2 -1
  35. data/app/views/shipit/commits/_commit.html.erb +9 -1
  36. data/app/views/shipit/deploys/rollback.html.erb +1 -1
  37. data/app/views/shipit/stacks/_header.html.erb +15 -3
  38. data/app/views/shipit/stacks/settings.html.erb +1 -1
  39. data/config/locales/en.yml +9 -5
  40. data/config/routes.rb +1 -0
  41. data/db/migrate/20170310164315_add_merged_at_on_pull_requests.rb +9 -0
  42. data/db/migrate/20170314145604_add_last_deployed_at_to_stack.rb +9 -0
  43. data/db/migrate/20170320124156_add_locked_to_commits.rb +5 -0
  44. data/lib/shipit/task_commands.rb +1 -0
  45. data/lib/shipit/version.rb +1 -1
  46. data/test/controllers/api/ccmenu_controller_test.rb +6 -0
  47. data/test/controllers/api/stacks_controller_test.rb +6 -0
  48. data/test/controllers/api/tasks_controller_test.rb +31 -0
  49. data/test/controllers/commits_controller_test.rb +18 -0
  50. data/test/dummy/db/development.sqlite3 +0 -0
  51. data/test/dummy/db/schema.rb +4 -1
  52. data/test/dummy/db/test.sqlite3 +0 -0
  53. data/test/dummy/db/test.sqlite3-journal +0 -0
  54. data/test/fixtures/shipit/commits.yml +1 -1
  55. data/test/fixtures/shipit/pull_requests.yml +33 -0
  56. data/test/fixtures/shipit/stacks.yml +4 -1
  57. data/test/jobs/github_sync_job_test.rb +49 -0
  58. data/test/jobs/merge_pull_requests_job_test.rb +18 -0
  59. data/test/models/commits_test.rb +71 -0
  60. data/test/models/deploy_spec_test.rb +15 -0
  61. data/test/models/deploys_test.rb +7 -0
  62. data/test/models/pull_request_test.rb +19 -1
  63. data/test/models/task_definitions_test.rb +9 -0
  64. data/test/models/undeployed_commits_test.rb +2 -7
  65. data/test/unit/deploy_commands_test.rb +7 -0
  66. data/test/unit/variable_definition_test.rb +10 -0
  67. metadata +15 -7
  68. data/app/assets/images/github.svg +0 -9
  69. data/app/assets/images/refresh.svg +0 -8
  70. data/app/assets/images/settings.svg +0 -33
  71. data/lib/snippets/deploy-to-gke +0 -161
@@ -1,4 +1,4 @@
1
- <li class="commit" id="commit-<%= commit.id %>">
1
+ <li class="commit <%= 'locked' if commit.locked? %>" id="commit-<%= commit.id %>">
2
2
  <%= render 'shipit/shared/author', author: commit.author %>
3
3
  <%= render commit.status %>
4
4
  <div class="commit-details">
@@ -14,6 +14,14 @@
14
14
  <%= timeago_tag(commit.committed_at, force: true) %>
15
15
  </p>
16
16
  </div>
17
+ <div class="commit-lock" >
18
+ <%= link_to stack_commit_path(commit.stack, commit), class: 'action-lock-commit', data: {tooltip: t('commit.lock')} do %>
19
+ <i class="icon icon--lock"></i>
20
+ <% end %>
21
+ <%= link_to stack_commit_path(commit.stack, commit), class: 'action-unlock-commit', data: {tooltip: t('commit.unlock'), confirm: t('commit.confirm_unlock')} do %>
22
+ <i class="icon icon--lock"></i>
23
+ <% end %>
24
+ </div>
17
25
  <div class="commit-actions">
18
26
  <%= deploy_button(commit) %>
19
27
  </div>
@@ -11,7 +11,7 @@
11
11
 
12
12
  <section>
13
13
  <header class="section-header">
14
- <h2>Commits included in this rollback</h2>
14
+ <h2>Commits that will be rolled back</h2>
15
15
  </header>
16
16
 
17
17
  <p><%= link_to_github_deploy(@rollback) %></p>
@@ -6,9 +6,6 @@
6
6
 
7
7
  <% content_for :primary_navigation do %>
8
8
  <%= link_to 'Refresh statuses & commits', stack_refresh_path(stack), method: 'post', class: "header__btn btn" %>
9
- <% stack.task_definitions.each do |definition| %>
10
- <%= link_to "#{definition.action}…", new_stack_tasks_path(stack, definition_id: definition.id), class: %w(header__btn stack-action btn trigger-deploy) %>
11
- <% end %>
12
9
  <% end %>
13
10
 
14
11
  <% content_for :secondary_navigation do %>
@@ -27,7 +24,22 @@
27
24
  <%= link_to "Pull Requests (#{stack.pull_requests.queued.count})", stack_pull_requests_path(stack) %>
28
25
  </li>
29
26
  <% end %>
27
+
28
+ <% if stack.task_definitions.present? %>
29
+ <li class="nav__list__item nav__list__item--has-children">
30
+ Tasks
31
+
32
+ <ul class="nav__sub__list">
33
+ <% stack.task_definitions.each do |definition| %>
34
+ <li class="nav__list__sub__item">
35
+ <%= link_to "#{definition.action}…", new_stack_tasks_path(stack, definition_id: definition.id), class: "trigger-deploy" %>
36
+ </li>
37
+ <% end %>
38
+ </ul>
39
+ </li>
40
+ <% end %>
30
41
  </ul>
42
+
31
43
  <ul class="nav__list nav__list--secondary">
32
44
  <% if stack.links.present? %>
33
45
  <% stack.links.each do |name, url| %>
@@ -74,7 +74,7 @@
74
74
  <div class="setting-section setting-ccmenu">
75
75
  <h5>Miscellaneous</h5>
76
76
  <div class="field-wrapper">
77
- <label>CCMenu URL</label>
77
+ <label>CCMenu URL (choose “Use URL as entered above” during CCMenu setup)</label>
78
78
  <input id="ccmenu-url" class="hidden" type="text" disabled />
79
79
  </div>
80
80
  <%= button_to "Fetch URL", "", class: 'btn', data: {remote: ccmenu_url_url(stack_id: @stack.to_param)} %>
@@ -20,21 +20,25 @@
20
20
  # available at http://guides.rubyonrails.org/i18n.html.
21
21
 
22
22
  en:
23
+ commit:
24
+ lock: This commit is safe to deploy. Click to mark it as unsafe.
25
+ unlock: This commit is unsafe to deploy. Click to mark it as safe.
26
+ confirm_unlock: Mark this commit as safe to deploy?
23
27
  deploy_button:
24
28
  hint:
25
29
  max_commits: It is recommended not to deploy more than %{maximum} commits at once.
26
30
  caption:
27
- pending: CI Pending...
28
- failure: CI Failure
29
- error: CI Error
31
+ pending: Pending CI
32
+ failure: Failing CI
33
+ error: Failing CI
30
34
  unknown: Not Run
31
35
  locked: Locked
32
- deploying: A Deploy is in Progress...
36
+ deploying: A Deploy is in Progress
33
37
  allowed: Deploy
34
38
  missing: Missing CI
35
39
  redeploy_button:
36
40
  caption:
37
- deploying: A Deploy is in Progress...
41
+ deploying: A Deploy is in Progress
38
42
  allowed: Redeploy
39
43
  locked: Locked
40
44
  deploy_spec:
data/config/routes.rb CHANGED
@@ -73,6 +73,7 @@ Shipit::Engine.routes.draw do
73
73
  get '/commit/:sha/checks/tail' => 'commit_checks#tail', as: :tail_commit_checks, defaults: {format: :json}
74
74
 
75
75
  resources :rollbacks, only: %i(create)
76
+ resources :commits, only: %i(update)
76
77
  resources :tasks, only: %i(show) do
77
78
  collection do
78
79
  get '' => 'tasks#index', as: :index
@@ -0,0 +1,9 @@
1
+ class AddMergedAtOnPullRequests < ActiveRecord::Migration[5.0]
2
+ def up
3
+ add_column :pull_requests, :merged_at, :datetime
4
+ end
5
+
6
+ def down
7
+ remove_column :pull_requests, :merged_at
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class AddLastDeployedAtToStack < ActiveRecord::Migration[5.0]
2
+ def up
3
+ add_column :stacks, :last_deployed_at, :datetime
4
+ end
5
+
6
+ def down
7
+ remove_column :stacks, :last_deployed_at
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class AddLockedToCommits < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :commits, :locked, :boolean, default: false, null: false
4
+ end
5
+ end
@@ -37,6 +37,7 @@ module Shipit
37
37
  'BUNDLE_PATH' => Rails.root.join('data', 'bundler').to_s,
38
38
  'SHIPIT_LINK' => permalink,
39
39
  'LAST_DEPLOYED_SHA' => @stack.last_deployed_commit.sha,
40
+ 'TASK_ID' => @task.id.to_s,
40
41
  ).merge(deploy_spec.machine_env).merge(@task.env)
41
42
  end
42
43
 
@@ -1,3 +1,3 @@
1
1
  module Shipit
2
- VERSION = '0.16.0'.freeze
2
+ VERSION = '0.17.0'.freeze
3
3
  end
@@ -42,6 +42,12 @@ module Shipit
42
42
  assert_payload 'lastBuildStatus', 'Failure'
43
43
  end
44
44
 
45
+ test "stacks with no deploys render correctly" do
46
+ stack = Stack.create!(repo_owner: 'foo', repo_name: 'bar')
47
+ get :show, params: {stack_id: stack.to_param}
48
+ assert_payload 'lastBuildStatus', 'Success'
49
+ end
50
+
45
51
  private
46
52
 
47
53
  def get_project_from_xml(xml)
@@ -101,6 +101,12 @@ module Shipit
101
101
  assert_response :ok
102
102
  assert_json 'id', @stack.id
103
103
  end
104
+
105
+ test "#show returns last_deployed_at column for stack" do
106
+ get :show, params: {id: @stack.to_param}
107
+ assert_response :ok
108
+ assert_json 'last_deployed_at', @stack.last_deployed_at
109
+ end
104
110
  end
105
111
  end
106
112
  end
@@ -24,11 +24,22 @@ module Shipit
24
24
  assert_json 'id', task.id
25
25
  end
26
26
 
27
+ test "#trigger returns 404 with unknown task" do
28
+ post :trigger, params: {stack_id: @stack.to_param, task_name: 'shave_the_yak'}
29
+ assert_response :not_found
30
+ end
31
+
27
32
  test "#trigger triggers a custom task" do
28
33
  post :trigger, params: {stack_id: @stack.to_param, task_name: 'restart'}
29
34
  assert_response :accepted
30
35
  assert_json 'type', 'task'
31
36
  assert_json 'status', 'pending'
37
+
38
+ expected_env = {
39
+ "FOO" => "1",
40
+ "BAR" => "0",
41
+ }
42
+ assert_equal expected_env, Shipit::Task.last.env
32
43
  end
33
44
 
34
45
  test "#trigger refuses to trigger a task with tasks not whitelisted" do
@@ -44,6 +55,26 @@ module Shipit
44
55
  assert_response :accepted
45
56
  assert_json 'type', 'task'
46
57
  assert_json 'status', 'pending'
58
+
59
+ expected_env = {
60
+ "FOO" => "bar",
61
+ "BAR" => "0",
62
+ }
63
+ assert_equal expected_env, Shipit::Task.last.env
64
+ end
65
+
66
+ test "#trigger triggers a task with explicitly passed and default variables" do
67
+ env = {'WALRUS' => 'overridden value'}
68
+ post :trigger, params: {stack_id: @stack.to_param, task_name: 'restart', env: env}
69
+ assert_response :accepted
70
+
71
+ # FOO and BAR are variables with a default value
72
+ expected_env = {
73
+ "FOO" => "1",
74
+ "BAR" => "0",
75
+ "WALRUS" => "overridden value",
76
+ }
77
+ assert_equal expected_env, Shipit::Task.last.env
47
78
  end
48
79
 
49
80
  test "#trigger returns a 404 when the task doesn't exist" do
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ module Shipit
4
+ class CommitsControllerTest < ActionController::TestCase
5
+ setup do
6
+ @stack = shipit_stacks(:shipit)
7
+ @commit = shipit_commits(:first)
8
+ session[:user_id] = shipit_users(:walrus).id
9
+ end
10
+
11
+ test "#update allows to lock a commit" do
12
+ refute_predicate @commit, :locked?
13
+ patch :update, params: {stack_id: @stack.to_param, id: @commit.id, commit: {locked: true}}
14
+ assert_response :ok
15
+ assert_predicate @commit.reload, :locked?
16
+ end
17
+ end
18
+ end
Binary file
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 20170221130336) do
13
+ ActiveRecord::Schema.define(version: 20170320124156) do
14
14
 
15
15
  create_table "api_clients", force: :cascade do |t|
16
16
  t.text "permissions", limit: 65535
@@ -59,6 +59,7 @@ ActiveRecord::Schema.define(version: 20170221130336) do
59
59
  t.integer "pull_request_number"
60
60
  t.string "pull_request_title", limit: 1024
61
61
  t.integer "pull_request_id"
62
+ t.boolean "locked", default: false, null: false
62
63
  t.index ["author_id"], name: "index_commits_on_author_id"
63
64
  t.index ["committer_id"], name: "index_commits_on_committer_id"
64
65
  t.index ["created_at"], name: "index_commits_on_created_at"
@@ -145,6 +146,7 @@ ActiveRecord::Schema.define(version: 20170221130336) do
145
146
  t.datetime "updated_at", null: false
146
147
  t.string "branch"
147
148
  t.datetime "revalidated_at"
149
+ t.datetime "merged_at"
148
150
  t.index ["head_id"], name: "index_pull_requests_on_head_id"
149
151
  t.index ["merge_requested_by_id"], name: "index_pull_requests_on_merge_requested_by_id"
150
152
  t.index ["stack_id", "github_id"], name: "index_pull_requests_on_stack_id_and_github_id", unique: true
@@ -173,6 +175,7 @@ ActiveRecord::Schema.define(version: 20170221130336) do
173
175
  t.datetime "continuous_delivery_delayed_since"
174
176
  t.datetime "locked_since"
175
177
  t.boolean "merge_queue_enabled", default: false, null: false
178
+ t.datetime "last_deployed_at"
176
179
  t.index ["repo_owner", "repo_name", "environment"], name: "stack_unicity", unique: true
177
180
  end
178
181
 
Binary file
Binary file
@@ -53,7 +53,7 @@ fourth:
53
53
  fifth:
54
54
  id: 5
55
55
  sha: 567578b362bf2b4df5903e1c7960929361c3abcd
56
- message: "fix all teh things"
56
+ message: "fix all the things"
57
57
  stack: shipit
58
58
  author: walrus
59
59
  committer: walrus
@@ -54,3 +54,36 @@ shipit_pending_not_mergeable_yet:
54
54
  mergeable: null
55
55
  additions: 23
56
56
  deletions: 43
57
+
58
+ shipit_pending_closed:
59
+ stack: shipit
60
+ number: 65
61
+ merge_status: pending
62
+ merge_requested_by: walrus
63
+ merge_requested_at: <%= 3.minute.ago.to_s(:db) %>
64
+ revalidated_at: <%= 3.minute.ago.to_s(:db) %>
65
+ github_id: 43243243243243
66
+ api_url: https://api.github.com/repos/shopify/shipit-engine/pulls/65
67
+ state: closed
68
+ branch: feature-64
69
+ head_id: 8
70
+ mergeable: null
71
+ additions: 23
72
+ deletions: 43
73
+
74
+ shipit_pending_merged:
75
+ stack: shipit
76
+ number: 66
77
+ merge_status: pending
78
+ merge_requested_by: walrus
79
+ merge_requested_at: <%= 3.minute.ago.to_s(:db) %>
80
+ merged_at: <%= 2.minute.ago.to_s(:db) %>
81
+ revalidated_at: <%= 3.minute.ago.to_s(:db) %>
82
+ github_id: 43243243243232
83
+ api_url: https://api.github.com/repos/shopify/shipit-engine/pulls/66
84
+ state: closed
85
+ branch: feature-64
86
+ head_id: 8
87
+ mergeable: null
88
+ additions: 23
89
+ deletions: 43
@@ -26,7 +26,8 @@ shipit:
26
26
  "description": "Restart app and job servers",
27
27
  "variables": [
28
28
  {"name": "FOO", "title": "Set to 0 to foo", "default": 1},
29
- {"name": "BAR", "title": "Set to 1 to bar", "default": 0}
29
+ {"name": "BAR", "title": "Set to 1 to bar", "default": 0},
30
+ {"name": "WALRUS", "title": "Walrus without a default value"}
30
31
  ],
31
32
  "steps": [
32
33
  "cap $ENVIRONMENT deploy:restart"
@@ -49,6 +50,7 @@ shipit:
49
50
  "allow_failures": ["ci/ok_to_fail"]
50
51
  }
51
52
  }
53
+ last_deployed_at: <%= 8.days.ago.to_s(:db) %>
52
54
  updated_at: <%= 8.days.ago.to_s(:db) %>
53
55
 
54
56
  cyclimse:
@@ -82,6 +84,7 @@ cyclimse:
82
84
  }
83
85
  }
84
86
  }
87
+ last_deployed_at: <%= 8.days.ago.to_s(:db) %>
85
88
  updated_at: <%= 8.days.ago.to_s(:db) %>
86
89
 
87
90
  undeployed_stack:
@@ -36,6 +36,55 @@ module Shipit
36
36
  assert shipit_commits(:fifth).reload.detached?
37
37
  end
38
38
 
39
+ test "#perform locks all commits leading to a revert" do
40
+ @stack.deploys_and_rollbacks.destroy_all
41
+
42
+ initial_queue = [
43
+ ["fix all the things", false],
44
+ ["yoloshipit!", false],
45
+ ["fix it!", false],
46
+ ["sheep it!", false],
47
+ ["lets go", false],
48
+ ]
49
+ assert_equal initial_queue, @stack.undeployed_commits.map { |c| [c.title, c.locked?] }
50
+
51
+ author = stub(
52
+ id: 1234,
53
+ login: 'bob',
54
+ name: 'Bob the Builder',
55
+ email: 'bob@bob.com',
56
+ date: '2011-04-14T16:00:49Z',
57
+ )
58
+ @job.expects(:fetch_missing_commits).returns([
59
+ [
60
+ stub(
61
+ sha: '36514755579bfb5bc313f403b216f4347a027990',
62
+ author: author,
63
+ committer: author,
64
+ stats: nil,
65
+ commit: stub(
66
+ sha: '36514755579bfb5bc313f403b216f4347a027990',
67
+ message: 'Revert "fix it!"',
68
+ author: author,
69
+ committer: author,
70
+ ),
71
+ ),
72
+ ],
73
+ shipit_commits(:fifth),
74
+ ])
75
+ @job.perform(stack_id: @stack.id)
76
+
77
+ final_queue = [
78
+ ['Revert "fix it!"', false],
79
+ ["fix all the things", true],
80
+ ["yoloshipit!", true],
81
+ ["fix it!", true],
82
+ ["sheep it!", false],
83
+ ["lets go", false],
84
+ ]
85
+ assert_equal final_queue, @stack.reload.undeployed_commits.map { |c| [c.title, c.locked?] }
86
+ end
87
+
39
88
  test "#fetch_missing_commits returns the commits in the reverse order if it doesn't know the parent" do
40
89
  last = stub(sha: 123)
41
90
  first = stub(sha: 345)
@@ -9,6 +9,8 @@ module Shipit
9
9
  @pending_pr = shipit_pull_requests(:shipit_pending)
10
10
  @unmergeable_pr = shipit_pull_requests(:shipit_pending_unmergeable)
11
11
  @not_ready_pr = shipit_pull_requests(:shipit_pending_not_mergeable_yet)
12
+ @closed_pr = shipit_pull_requests(:shipit_pending_closed)
13
+ @merged_pr = shipit_pull_requests(:shipit_pending_merged)
12
14
  end
13
15
 
14
16
  test "#perform rejects unmergeable PRs and merge the others" do
@@ -20,6 +22,8 @@ module Shipit
20
22
  }.to_json)
21
23
  branch_url = "https://api.github.com/repos/shopify/shipit-engine/git/refs/heads/feature-62"
22
24
  FakeWeb.register_uri(:delete, branch_url, status: %w(204 No content))
25
+ pulls_url = "https://api.github.com/repos/shopify/shipit-engine/pulls?base=feature-62"
26
+ FakeWeb.register_uri(:get, pulls_url, status: %w(200 OK), body: '[]')
23
27
 
24
28
  @job.perform(@stack)
25
29
 
@@ -55,5 +59,19 @@ module Shipit
55
59
  end
56
60
  assert_predicate @pending_pr.reload, :pending?
57
61
  end
62
+
63
+ test "#perform cancels merge requests for closed PRs" do
64
+ @pending_pr.cancel!
65
+ PullRequest.any_instance.stubs(:refresh!)
66
+ @job.perform(@stack)
67
+ assert_predicate @closed_pr.reload, :canceled?
68
+ end
69
+
70
+ test "#perform completes merge requests for already merged PRs" do
71
+ @pending_pr.cancel!
72
+ PullRequest.any_instance.stubs(:refresh!)
73
+ @job.perform(@stack)
74
+ assert_predicate @merged_pr.reload, :merged?
75
+ end
58
76
  end
59
77
  end