shipit-engine 0.37.0 → 0.39.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -3
  3. data/app/controllers/shipit/api/base_controller.rb +2 -2
  4. data/app/controllers/shipit/api/deploys_controller.rb +5 -1
  5. data/app/controllers/shipit/api/stacks_controller.rb +25 -1
  6. data/app/helpers/shipit/api_clients_helper.rb +12 -0
  7. data/app/jobs/shipit/continuous_delivery_job.rb +4 -1
  8. data/app/models/shipit/api_client.rb +1 -1
  9. data/app/models/shipit/commit_deployment_status.rb +0 -1
  10. data/app/models/shipit/delivery.rb +1 -1
  11. data/app/models/shipit/deploy_spec/file_system.rb +14 -2
  12. data/app/models/shipit/hook.rb +1 -1
  13. data/app/models/shipit/pull_request.rb +1 -1
  14. data/app/models/shipit/stack.rb +21 -5
  15. data/app/models/shipit/task.rb +7 -3
  16. data/app/models/shipit/task_execution_strategy/default.rb +1 -1
  17. data/app/models/shipit/user.rb +2 -0
  18. data/app/views/shipit/_variables.html.erb +1 -1
  19. data/app/views/shipit/api_clients/show.html.erb +1 -1
  20. data/app/views/shipit/merge_status/failure.html.erb +1 -1
  21. data/app/views/shipit/missing_settings.html.erb +1 -1
  22. data/config/secrets.development.example.yml +1 -1
  23. data/config/secrets.development.shopify.yml +1 -1
  24. data/db/migrate/20230703181143_change_commit_deployment_statuses_github_id_to_big_int.rb +5 -0
  25. data/lib/shipit/engine.rb +1 -1
  26. data/lib/shipit/github_app.rb +0 -1
  27. data/lib/shipit/octokit_check_runs.rb +1 -3
  28. data/lib/shipit/octokit_iterator.rb +2 -0
  29. data/lib/shipit/stack_commands.rb +11 -1
  30. data/lib/shipit/task_commands.rb +1 -1
  31. data/lib/shipit/version.rb +1 -1
  32. data/lib/shipit.rb +1 -1
  33. data/test/controllers/api/base_controller_test.rb +1 -1
  34. data/test/controllers/api/ccmenu_controller_test.rb +1 -1
  35. data/test/controllers/api/commits_controller_test.rb +1 -1
  36. data/test/controllers/api/deploys_controller_test.rb +25 -1
  37. data/test/controllers/api/hooks_controller_test.rb +1 -1
  38. data/test/controllers/api/locks_controller_test.rb +1 -1
  39. data/test/controllers/api/merge_requests_controller_test.rb +1 -1
  40. data/test/controllers/api/outputs_controller_test.rb +1 -1
  41. data/test/controllers/api/release_statuses_controller_test.rb +1 -1
  42. data/test/controllers/api/rollback_controller_test.rb +1 -1
  43. data/test/controllers/api/stacks_controller_test.rb +52 -1
  44. data/test/controllers/api/tasks_controller_test.rb +1 -1
  45. data/test/controllers/stacks_controller_test.rb +1 -1
  46. data/test/controllers/tasks_controller_test.rb +8 -1
  47. data/test/dummy/config/application.rb +2 -1
  48. data/test/dummy/config/initializers/0_load_development_secrets.rb +2 -2
  49. data/test/dummy/config/secrets.development.json +3 -0
  50. data/test/dummy/config/secrets.test.json +21 -0
  51. data/test/dummy/db/schema.rb +2 -2
  52. data/test/helpers/api_helper.rb +13 -0
  53. data/test/models/commit_deployment_status_test.rb +0 -1
  54. data/test/models/merge_request_test.rb +4 -1
  55. data/test/models/shipit/{stacks_test.rb → stack_test.rb} +48 -5
  56. data/test/models/users_test.rb +8 -0
  57. data/test/test_helper.rb +2 -2
  58. data/test/unit/deploy_commands_test.rb +94 -6
  59. data/test/unit/github_app_test.rb +1 -1
  60. metadata +15 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 174fee8bf3ed460fa137cbe666f639fec2218d0617b4860dcede08d38ed6d93d
4
- data.tar.gz: 739d8f122ead25b8f1053f954686e4ddd574bc17b544de9b69dce5af7635425c
3
+ metadata.gz: d14e4fec687523820d46bf58196894deb71b3acb79358059b743d33c31bf9305
4
+ data.tar.gz: e5d756e9bc4f452408f40d0a3f1f2d6f06cbeceb7544ae47d91b245acb1fc83b
5
5
  SHA512:
6
- metadata.gz: 7b3118fb7bc39e0c8cddad0444d34c39e935bcc192010dec3b27b2bddd9947a770573a959b13fe26661eb8874963b10cdb8ab2382d6eec811ebd8cd87322cc41
7
- data.tar.gz: cd173c7dc66f31a90e878ed9a2da9724132286c93f2a9c168a5593f81ffbfe3c6f25161095fafe7df1e9d7c2561339ca0c4051ae856c78d8698d382e8d65818c
6
+ metadata.gz: e4a7e88bdf8fe9c40fe6520054fad67a72af184524bb1a8f3a20c0bea07b858cf5d568b272ce0a95060c8bfa2c64b5cb1adec7487a877e23f37e6a8bf3f143ed
7
+ data.tar.gz: 6cab2f24a84a81251991dc20b23c4d9f966fa8b98f053b904b34227850efca196133ec2c395a5e0c8444b8c41d6672d1362058fd1c90e543e7b1c97d6f07732a
data/README.md CHANGED
@@ -25,8 +25,8 @@ This guide aims to help you [set up](#installation-and-setup), [use](#using-ship
25
25
  **II. USING SHIPIT**
26
26
 
27
27
  * [Adding stacks](#adding-stacks)
28
- * [Working on stacks](#working-on-stacks),
29
- * [Configuring stacks](#configuring-stacks).
28
+ * [Working on stacks](#working-on-stacks)
29
+ * [Configuring stacks](#configuring-stacks)
30
30
 
31
31
  **III. REFERENCE**
32
32
 
@@ -357,6 +357,11 @@ For example:
357
357
  fetch:
358
358
  curl --silent https://app.example.com/services/ping/version
359
359
  ```
360
+
361
+ **Note:** Currently, deployments in emergency mode are configured to occur concurrently via [the `build_deploy` method](https://github.com/Shopify/shipit-engine/blob/main/app/models/shipit/stack.rb),
362
+ whose `allow_concurrency` keyword argument defaults to `force`, where `force` is true when emergency mode is enabled.
363
+ If you'd like to separate these two from one another, override this method as desired in your service.
364
+
360
365
  <h3 id="kubernetes">Kubernetes</h3>
361
366
 
362
367
  **<code>kubernetes</code>** allows to specify a Kubernetes namespace and context to deploy to.
@@ -641,7 +646,7 @@ Your deploy scripts have access to the following environment variables:
641
646
  * `GITHUB_REPO_OWNER`: The GitHub username of the repository owner for the current deploy/task.
642
647
  * `EMAIL`: Email of the user that triggered the deploy/task (if available)
643
648
  * `ENVIRONMENT`: The stack environment (e.g `production` / `staging`)
644
- * `BRANCH`: The stack branch (e.g `master`)
649
+ * `BRANCH`: The stack branch (e.g `main`)
645
650
  * `LAST_DEPLOYED_SHA`: The git SHA of the last deployed commit
646
651
  * `DIFF_LINK`: URL to the diff on GitHub.
647
652
  * `TASK_ID`: ID of the task that is running
@@ -93,8 +93,8 @@ module Shipit
93
93
  render(status: :not_found, json: { status: '404', error: 'Not Found' })
94
94
  end
95
95
 
96
- def conflict(_error)
97
- render(status: :conflict, json: { status: '409', error: 'Conflict' })
96
+ def conflict(error)
97
+ render(status: :conflict, json: { status: '409', error: error.message })
98
98
  end
99
99
  end
100
100
  end
@@ -11,6 +11,7 @@ module Shipit
11
11
  params do
12
12
  requires :sha, String, length: { in: 6..40 }
13
13
  accepts :force, Boolean, default: false
14
+ accepts :allow_concurrency, Boolean
14
15
  accepts :require_ci, Boolean, default: false
15
16
  accepts :env, Hash, default: {}
16
17
  end
@@ -18,7 +19,10 @@ module Shipit
18
19
  commit = stack.commits.by_sha(params.sha) || param_error!(:sha, 'Unknown revision')
19
20
  param_error!(:force, "Can't deploy a locked stack") if !params.force && stack.locked?
20
21
  param_error!(:require_ci, "Commit is not deployable") if params.require_ci && !commit.deployable?
21
- deploy = stack.trigger_deploy(commit, current_user, env: params.env, force: params.force)
22
+
23
+ allow_concurrency = params.allow_concurrency.nil? ? params.force : params.allow_concurrency
24
+ deploy = stack.trigger_deploy(commit, current_user, env: params.env, force: params.force,
25
+ allow_concurrency: allow_concurrency)
22
26
  render_resource(deploy, status: :accepted)
23
27
  end
24
28
  end
@@ -46,9 +46,13 @@ module Shipit
46
46
  accepts :ignore_ci, Boolean
47
47
  accepts :merge_queue_enabled, Boolean
48
48
  accepts :continuous_deployment, Boolean
49
+ accepts :archived, Boolean
49
50
  end
50
51
  def update
51
- stack.update(params)
52
+ stack.update(update_params)
53
+
54
+ update_archived
55
+
52
56
  render_resource(stack)
53
57
  end
54
58
 
@@ -78,6 +82,26 @@ module Shipit
78
82
  @stack ||= stacks.from_param!(params[:id])
79
83
  end
80
84
 
85
+ def update_archived
86
+ if key?(:archived)
87
+ if params[:archived]
88
+ stack.archive!(nil)
89
+ elsif stack.archived?
90
+ stack.unarchive!
91
+ end
92
+ end
93
+ end
94
+
95
+ def key?(key)
96
+ params.to_h.key?(key)
97
+ end
98
+
99
+ def update_params
100
+ params.select do |key, _|
101
+ %i(environment branch deploy_url ignore_ci merge_queue_enabled continuous_deployment).include?(key)
102
+ end
103
+ end
104
+
81
105
  def repository
82
106
  @repository ||= Repository.find_or_create_by(owner: repo_owner, name: repo_name)
83
107
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module Shipit
3
+ module ApiClientsHelper
4
+ def api_client_token(api_client)
5
+ if api_client.created_at >= 5.minutes.ago && current_user == api_client.creator
6
+ api_client.authentication_token
7
+ else
8
+ "#{api_client.authentication_token[0..5]}************************"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -8,7 +8,10 @@ module Shipit
8
8
 
9
9
  def perform(stack)
10
10
  return unless stack.continuous_deployment?
11
- return if stack.active_task?
11
+
12
+ # checks if there are any tasks running, including concurrent tasks
13
+ return if stack.occupied?
14
+
12
15
  stack.trigger_continuous_delivery
13
16
  end
14
17
  end
@@ -8,7 +8,7 @@ module Shipit
8
8
 
9
9
  validates :creator, :name, presence: true
10
10
 
11
- serialize :permissions, Shipit.serialized_column(:permissions, type: Array)
11
+ serialize :permissions, coder: Shipit.serialized_column(:permissions, type: Array)
12
12
  PERMISSIONS = %w(
13
13
  read:stack
14
14
  write:stack
@@ -48,7 +48,6 @@ module Shipit
48
48
  client.create_deployment_status(
49
49
  commit_deployment.api_url,
50
50
  status,
51
- accept: 'application/vnd.github.flash-preview+json',
52
51
  target_url: url_helpers.stack_deploy_url(stack, task),
53
52
  description: description.truncate(DESCRIPTION_CHARACTER_LIMIT_ON_GITHUB),
54
53
  environment_url: stack.deploy_url,
@@ -9,7 +9,7 @@ module Shipit
9
9
  validates :url, presence: true, url: { no_local: true, allow_blank: true }
10
10
  validates :content_type, presence: true
11
11
 
12
- serialize :response_headers, SafeJSON
12
+ serialize :response_headers, coder: SafeJSON
13
13
 
14
14
  after_commit :purge_old_deliveries, on: :create
15
15
 
@@ -101,11 +101,23 @@ module Shipit
101
101
  end
102
102
 
103
103
  def shipit_file_names_in_priority_order
104
- ["#{app_name}.#{@env}.yml", "#{app_name}.yml", "shipit.#{@env}.yml", "shipit.yml"].uniq
104
+ [
105
+ "#{app_name}.#{@env}.yml",
106
+ ".shipit/#{app_name}.#{@env}.yml",
107
+
108
+ "#{app_name}.yml",
109
+ ".shipit/#{app_name}.yml",
110
+
111
+ "shipit.#{@env}.yml",
112
+ ".shipit/#{@env}.yml",
113
+
114
+ "shipit.yml",
115
+ ".shipit/shipit.yml",
116
+ ].uniq
105
117
  end
106
118
 
107
119
  def bare_shipit_filenames
108
- ["#{app_name}.yml", "shipit.yml"].uniq
120
+ ["#{app_name}.yml", "shipit.yml", ".shipit/#{app_name}.yml", ".shipit/shipit.yml"].uniq
109
121
  end
110
122
 
111
123
  def config_file_path
@@ -87,7 +87,7 @@ module Shipit
87
87
  validates :content_type, presence: true, inclusion: { in: CONTENT_TYPES.keys }
88
88
  validates :events, presence: true, subset: { of: EVENTS }
89
89
 
90
- serialize :events, Shipit::CSVSerializer
90
+ serialize :events, coder: Shipit::CSVSerializer
91
91
 
92
92
  scope :global, -> { where(stack_id: nil) }
93
93
  scope :scoped_to, ->(stack) { where(stack_id: stack.id) }
@@ -11,7 +11,7 @@ module Shipit
11
11
  has_many :pull_request_assignments
12
12
  has_many :assignees, class_name: :User, through: :pull_request_assignments, source: :user
13
13
 
14
- serialize :labels, Shipit.serialized_column(:labels, type: Array)
14
+ serialize :labels, coder: Shipit.serialized_column(:labels, type: Array)
15
15
 
16
16
  after_create_commit :emit_create_hooks
17
17
  after_update_commit :emit_update_hooks
@@ -101,7 +101,7 @@ module Shipit
101
101
 
102
102
  validates :lock_reason, length: { maximum: 4096 }
103
103
 
104
- serialize :cached_deploy_spec, DeploySpec
104
+ serialize :cached_deploy_spec, coder: DeploySpec
105
105
  delegate(
106
106
  :provisioning_handler_name,
107
107
  :find_task_definition,
@@ -150,14 +150,14 @@ module Shipit
150
150
  task
151
151
  end
152
152
 
153
- def build_deploy(until_commit, user, env: nil, force: false)
153
+ def build_deploy(until_commit, user, env: nil, force: false, allow_concurrency: force)
154
154
  since_commit = last_deployed_commit.presence || commits.first
155
155
  deploys.build(
156
156
  user_id: user.id,
157
157
  until_commit: until_commit,
158
158
  since_commit: since_commit,
159
159
  env: filter_deploy_envs(env&.to_h || {}),
160
- allow_concurrency: force,
160
+ allow_concurrency: allow_concurrency,
161
161
  ignored_safeties: force || !until_commit.deployable?,
162
162
  max_retries: retries_on_deploy,
163
163
  )
@@ -226,8 +226,12 @@ module Shipit
226
226
 
227
227
  def next_commit_to_deploy
228
228
  commits_to_deploy = commits.order(id: :asc).newer_than(last_deployed_commit).reachable.preload(:statuses)
229
- commits_to_deploy = commits_to_deploy.limit(maximum_commits_per_deploy) if maximum_commits_per_deploy
230
- commits_to_deploy.to_a.reverse.find(&:deployable?)
229
+ if maximum_commits_per_deploy
230
+ commits_with_max_applied = commits_to_deploy.limit(maximum_commits_per_deploy)
231
+ deployable_commits(commits_with_max_applied) || deployable_commits(commits_to_deploy)
232
+ else
233
+ deployable_commits(commits_to_deploy)
234
+ end
231
235
  end
232
236
 
233
237
  def deployed_too_recently?
@@ -453,6 +457,14 @@ module Shipit
453
457
  @active_task ||= tasks.current
454
458
  end
455
459
 
460
+ def occupied?
461
+ !!occupied
462
+ end
463
+
464
+ def occupied
465
+ @occupied ||= tasks.active.last
466
+ end
467
+
456
468
  def locked?
457
469
  lock_reason.present?
458
470
  end
@@ -620,6 +632,10 @@ module Shipit
620
632
 
621
633
  private
622
634
 
635
+ def deployable_commits(commits)
636
+ commits.to_a.reverse.find(&:deployable?)
637
+ end
638
+
623
639
  def clear_cache
624
640
  remove_instance_variable(:@active_task) if defined?(@active_task)
625
641
  end
@@ -3,7 +3,11 @@ module Shipit
3
3
  class Task < Record
4
4
  include DeferredTouch
5
5
 
6
- ConcurrentTaskRunning = Class.new(StandardError)
6
+ class ConcurrentTaskRunning < StandardError
7
+ def message
8
+ "A task is already running."
9
+ end
10
+ end
7
11
 
8
12
  PRESENCE_CHECK_TIMEOUT = 30
9
13
  ACTIVE_STATUSES = %w(pending running aborting).freeze
@@ -54,8 +58,8 @@ module Shipit
54
58
  end
55
59
  end
56
60
 
57
- serialize :definition, TaskDefinition
58
- serialize :env, Shipit.serialized_column(:env, coder: EnvHash)
61
+ serialize :definition, coder: TaskDefinition
62
+ serialize :env, coder: Shipit.serialized_column(:env, coder: EnvHash)
59
63
 
60
64
  scope :success, -> { where(status: 'success') }
61
65
  scope :completed, -> { where(status: COMPLETED_STATUSES) }
@@ -70,7 +70,7 @@ module Shipit
70
70
  @task.acquire_git_cache_lock do
71
71
  @task.ping
72
72
  unless @commands.fetched?(@task.until_commit).tap(&:run).success?
73
- capture!(@commands.fetch)
73
+ capture!(@commands.fetch_commit(@task.until_commit))
74
74
  end
75
75
  end
76
76
  end
@@ -95,6 +95,8 @@ module Shipit
95
95
  update!(github_user: Shipit.github.api.user(github_id))
96
96
  rescue Octokit::NotFound
97
97
  identify_renamed_user!
98
+ rescue Octokit::Forbidden
99
+ Rails.logger.info("User #{name}, github_id #{github_id} has forbidden access to their GitHub, likely deleted.")
98
100
  end
99
101
 
100
102
  def github_user=(github_user)
@@ -9,7 +9,7 @@
9
9
  <% if variable.select %>
10
10
  <%= field.select variable.name, options_for_select([["Please select...", { disabled: "disabled" }]] + variable.select, variable.default || "Please select...") %>
11
11
  <% else %>
12
- <%= field.text_field variable.name, value: variable.default %>
12
+ <%= field.text_field variable.name, value: params[variable.name].presence || variable.default %>
13
13
  <% end %>
14
14
  <%= field.label variable.name, variable.title || variable.name %>
15
15
  </p>
@@ -10,7 +10,7 @@
10
10
  <section>
11
11
  <h3>Authentication token:</h3>
12
12
  <code style="background-color: yellow">
13
- <b><%= @api_client.authentication_token %></b>
13
+ <b><%= api_client_token(@api_client) %></b>
14
14
  </code>
15
15
  </section>
16
16
 
@@ -15,7 +15,7 @@
15
15
  </h4>
16
16
  <span class="status-meta">
17
17
  <%= link_to @stack.to_param, stack_url(@stack), target: '_blank', rel: 'noopener' %>
18
- <strong>master branch is failing!</strong>
18
+ <strong>main branch is failing!</strong>
19
19
  </span>
20
20
  <%= render 'commit_count_warning' if display_commit_count_warning?(params[:commits].to_i) %>
21
21
  </div>
@@ -22,7 +22,7 @@
22
22
 
23
23
  <p id="github_app">
24
24
  Config:
25
- <% if Rails.application.secrets.github.present? %>
25
+ <% if Rails.application.credentials.github.present? %>
26
26
  Success!
27
27
  <% else %>
28
28
  <span class="missing">
@@ -1,7 +1,7 @@
1
1
  host: 'localhost:3000'
2
2
  redis_url: 'redis://127.0.0.1:6379/0'
3
3
 
4
- # For creating an app see: https://github.com/Shopify/shipit-engine/blob/master/docs/setup.md#creating-the-github-app
4
+ # For creating an app see: https://github.com/Shopify/shipit-engine/blob/main/docs/setup.md#creating-the-github-app
5
5
  # Can be obtained there: https://github.com/settings/apps
6
6
  # Set the "Authorization callback URL" as `<host>/github/auth/github/callback`
7
7
 
@@ -1,7 +1,7 @@
1
1
  host: 'shipit-engine.myshopify.io'
2
2
  redis_url: 'redis://shipit-engine.railgun:6379'
3
3
 
4
- # For creating an app see: https://github.com/Shopify/shipit-engine/blob/master/docs/setup.md#creating-the-github-app
4
+ # For creating an app see: https://github.com/Shopify/shipit-engine/blob/main/docs/setup.md#creating-the-github-app
5
5
 
6
6
  github:
7
7
  somegithuborg:
@@ -0,0 +1,5 @@
1
+ class ChangeCommitDeploymentStatusesGithubIdToBigInt < ActiveRecord::Migration[7.0]
2
+ def change
3
+ change_column :commit_deployment_statuses, :github_id, :bigint
4
+ end
5
+ end
data/lib/shipit/engine.rb CHANGED
@@ -21,7 +21,7 @@ module Shipit
21
21
  Shipit::Engine.routes.default_url_options[:host] = Shipit.host
22
22
  Pubsubstub.redis_url = Shipit.redis_url.to_s
23
23
 
24
- Rails.application.secrets.deep_symbolize_keys!
24
+ Rails.application.credentials.deep_symbolize_keys!
25
25
 
26
26
  app.config.assets.paths << Emoji.images_path
27
27
  app.config.assets.precompile += %w(
@@ -103,7 +103,6 @@ module Shipit
103
103
  ) do
104
104
  response = new_client(bearer_token: authentication_payload).create_app_installation_access_token(
105
105
  installation_id,
106
- accept: 'application/vnd.github.machine-man-preview+json',
107
106
  )
108
107
  token = Token.from_github(response)
109
108
  raise AuthenticationFailed if token.blank?
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module OctokitCheckRuns
3
3
  def check_runs(repo, sha, options = {})
4
- paginate("#{Octokit::Repository.path(repo)}/commits/#{sha}/check-runs", options.reverse_merge(
5
- accept: 'application/vnd.github.antiope-preview+json',
6
- ))
4
+ paginate("#{Octokit::Repository.path(repo)}/commits/#{sha}/check-runs", options)
7
5
  end
8
6
  end
9
7
 
@@ -16,6 +16,8 @@ module Shipit
16
16
  response = @response
17
17
 
18
18
  loop do
19
+ return unless response.present?
20
+
19
21
  response.data.each(&block)
20
22
  return unless response.rels[:next]
21
23
  response = response.rels[:next].get
@@ -13,6 +13,16 @@ module Shipit
13
13
  super.merge(@stack.env)
14
14
  end
15
15
 
16
+ def fetch_commit(commit)
17
+ create_directories
18
+ if valid_git_repository?(@stack.git_path)
19
+ git('fetch', 'origin', '--quiet', '--tags', commit.sha, env: env, chdir: @stack.git_path)
20
+ else
21
+ @stack.clear_git_cache!
22
+ git_clone(@stack.repo_git_url, @stack.git_path, branch: @stack.branch, env: env, chdir: @stack.deploys_path)
23
+ end
24
+ end
25
+
16
26
  def fetch
17
27
  create_directories
18
28
  if valid_git_repository?(@stack.git_path)
@@ -96,7 +106,7 @@ module Shipit
96
106
  .success?
97
107
  end
98
108
 
99
- def git_clone(url, path, branch: 'master', **kwargs)
109
+ def git_clone(url, path, branch: 'main', **kwargs)
100
110
  git('clone', '--quiet', *modern_git_args, '--recursive', '--branch', branch, url, path, **kwargs)
101
111
  end
102
112
 
@@ -2,7 +2,7 @@
2
2
  # rubocop:disable Lint/MissingSuper
3
3
  module Shipit
4
4
  class TaskCommands < Commands
5
- delegate :fetch, :fetched?, to: :stack_commands
5
+ delegate :fetch_commit, :fetch, :fetched?, to: :stack_commands
6
6
 
7
7
  def initialize(task)
8
8
  @task = task
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Shipit
3
- VERSION = '0.37.0'
3
+ VERSION = '0.39.0'
4
4
  end
data/lib/shipit.rb CHANGED
@@ -291,7 +291,7 @@ module Shipit
291
291
  end
292
292
 
293
293
  def secrets
294
- Rails.application.secrets
294
+ Rails.application.credentials
295
295
  end
296
296
  end
297
297
 
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class BaseControllerTest < ActionController::TestCase
6
+ class BaseControllerTest < ApiControllerTestCase
7
7
  test "authentication is required" do
8
8
  get :index
9
9
  assert_response :unauthorized
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class CCMenuControllerTest < ActionController::TestCase
6
+ class CCMenuControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  authenticate!
9
9
  @stack = shipit_stacks(:shipit)
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class CommitsControllerTest < ActionController::TestCase
6
+ class CommitsControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  @stack = shipit_stacks(:shipit)
9
9
  authenticate!
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class DeploysControllerTest < ActionController::TestCase
6
+ class DeploysControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  authenticate!
9
9
  @user = shipit_users(:walrus)
@@ -81,6 +81,7 @@ module Shipit
81
81
  end
82
82
 
83
83
  assert_response :conflict
84
+ assert_json 'error', 'A task is already running.'
84
85
  end
85
86
 
86
87
  test "#create refuses to deploy unsuccessful commits if the require_ci flag is passed" do
@@ -119,6 +120,29 @@ module Shipit
119
120
  assert_response :accepted
120
121
  assert_json 'status', 'pending'
121
122
  end
123
+
124
+ test "#create uses allow_concurrency param when provided" do
125
+ @stack.update!(lock_reason: 'Something broken')
126
+
127
+ assert_difference -> { @stack.deploys.count }, 1 do
128
+ post :create, params: { stack_id: @stack.to_param, sha: @commit.sha, force: 'true', allow_concurrency: 'false' }
129
+ end
130
+ assert_response :accepted
131
+ assert_json 'status', 'pending'
132
+ refute @stack.deploys.last.allow_concurrency
133
+ end
134
+
135
+ test "#create defaults allow_concurrency to force param when not provided" do
136
+ @stack.update!(lock_reason: 'Something broken')
137
+ expected_force = true
138
+
139
+ assert_difference -> { @stack.deploys.count }, 1 do
140
+ post :create, params: { stack_id: @stack.to_param, sha: @commit.sha, force: expected_force }
141
+ end
142
+ assert_response :accepted
143
+ assert_json 'status', 'pending'
144
+ assert_equal expected_force, @stack.deploys.last.allow_concurrency
145
+ end
122
146
  end
123
147
  end
124
148
  end
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class HooksControllerTest < ActionController::TestCase
6
+ class HooksControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  authenticate!
9
9
  @stack = shipit_stacks(:shipit)
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class LocksControllerTest < ActionController::TestCase
6
+ class LocksControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  authenticate!
9
9
  @stack = shipit_stacks(:shipit)
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class MergeRequestsControllerTest < ActionController::TestCase
6
+ class MergeRequestsControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  @stack = shipit_stacks(:shipit)
9
9
  @merge_request = shipit_merge_requests(:shipit_pending)
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class OutputsControllerTest < ActionController::TestCase
6
+ class OutputsControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  @stack = shipit_stacks(:shipit)
9
9
  authenticate!
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class ReleaseStatusesControllerTest < ActionController::TestCase
6
+ class ReleaseStatusesControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  authenticate!
9
9
  @stack = shipit_stacks(:shipit_canaries)
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class RollbacksControllerTest < ActionController::TestCase
6
+ class RollbacksControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  authenticate!
9
9
  @user = shipit_users(:walrus)
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class StacksControllerTest < ActionController::TestCase
6
+ class StacksControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  authenticate!
9
9
  @stack = shipit_stacks(:shipit)
@@ -114,6 +114,57 @@ module Shipit
114
114
  refute @stack.continuous_deployment
115
115
  end
116
116
 
117
+ test "#update does not perform archive when key is not provided" do
118
+ refute_predicate @stack, :archived?
119
+ refute_predicate @stack, :locked?
120
+
121
+ patch :update, params: { id: @stack.to_param }
122
+
123
+ @stack.reload
124
+ refute_predicate @stack, :archived?
125
+ refute_predicate @stack, :locked?
126
+ end
127
+
128
+ test "#update does not perform unarchive when key is not provided" do
129
+ @stack.archive!(shipit_users(:walrus))
130
+ assert_predicate @stack, :locked?
131
+ assert_predicate @stack, :archived?
132
+
133
+ patch :update, params: { id: @stack.to_param }
134
+
135
+ @stack.reload
136
+ assert_predicate @stack, :locked?
137
+ assert_predicate @stack, :archived?
138
+ end
139
+
140
+ test "#update allows to archive the stack" do
141
+ refute_predicate @stack, :archived?
142
+ refute_predicate @stack, :locked?
143
+
144
+ patch :update, params: { id: @stack.to_param, archived: true }
145
+
146
+ @stack.reload
147
+ assert_predicate @stack, :locked?
148
+ assert_predicate @stack, :archived?
149
+ assert_instance_of AnonymousUser, @stack.lock_author
150
+ assert_equal "Archived", @stack.lock_reason
151
+ end
152
+
153
+ test "#update allows to unarchive the stack" do
154
+ @stack.archive!(shipit_users(:walrus))
155
+ assert_predicate @stack, :locked?
156
+ assert_predicate @stack, :archived?
157
+
158
+ patch :update, params: { id: @stack.to_param, archived: false }
159
+
160
+ @stack.reload
161
+ refute_predicate @stack, :archived?
162
+ refute_predicate @stack, :locked?
163
+ assert_nil @stack.locked_since
164
+ assert_nil @stack.lock_reason
165
+ assert_instance_of AnonymousUser, @stack.lock_author
166
+ end
167
+
117
168
  test "#index returns a list of stacks" do
118
169
  stack = Stack.last
119
170
  get :index
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
 
4
4
  module Shipit
5
5
  module Api
6
- class TasksControllerTest < ActionController::TestCase
6
+ class TasksControllerTest < ApiControllerTestCase
7
7
  setup do
8
8
  @stack = shipit_stacks(:shipit)
9
9
  @user = shipit_users(:walrus)
@@ -10,7 +10,7 @@ module Shipit
10
10
  end
11
11
 
12
12
  test "validates that Shipit.github is present" do
13
- Rails.application.secrets.stubs(:github).returns(nil)
13
+ Rails.application.credentials.stubs(:github).returns(nil)
14
14
  get :index
15
15
  assert_select "#github_app .missing"
16
16
  assert_select ".missing", count: 1
@@ -11,9 +11,16 @@ module Shipit
11
11
  session[:user_id] = shipit_users(:walrus).id
12
12
  end
13
13
 
14
- test "tasks defined in the shipit.yml can be displayed" do
14
+ test "tasks defined in the shipit.yml can be displayed with default variable values" do
15
15
  get :new, params: { stack_id: @stack, definition_id: @definition.id }
16
16
  assert_response :ok
17
+ assert_select 'input[name="task[env][FOO]"][value="1"]'
18
+ end
19
+
20
+ test "it is possible to provide a default value override for a task" do
21
+ get :new, params: { stack_id: @stack, definition_id: @definition.id, FOO: '42' }
22
+ assert_response :ok
23
+ assert_select 'input[name="task[env][FOO]"][value="42"]'
17
24
  end
18
25
 
19
26
  test "tasks defined in the shipit.yml can't be triggered if the stack is being deployed" do
@@ -17,6 +17,7 @@ end
17
17
 
18
18
  module Shipit
19
19
  class Application < Rails::Application
20
- config.load_defaults 7.0
20
+ config.load_defaults 7.1
21
+ config.active_record.encryption.support_sha1_for_non_deterministic_encryption = true
21
22
  end
22
23
  end
@@ -2,8 +2,8 @@ local_secrets = Shipit::Engine.root.join('config/secrets.development.yml')
2
2
  if local_secrets.exist?
3
3
  secrets = YAML.load(local_secrets.read).deep_symbolize_keys
4
4
  if Rails.env.development?
5
- Rails.application.secrets.deep_merge!(secrets)
5
+ Rails.application.credentials.deep_merge!(secrets)
6
6
  elsif Rails.env.test?
7
- Rails.application.secrets.merge!(redis_url: secrets[:redis_url])
7
+ Rails.application.credentials.merge!(redis_url: secrets[:redis_url])
8
8
  end
9
9
  end
@@ -0,0 +1,3 @@
1
+ {
2
+ "secret_key_base": "s3cr3ts3cr3ts3cr3ts3cr3ts3cr3ts3cr3t"
3
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "host": "shipit.com",
3
+ "secret_key_base": "s3cr3ts3cr3ts3cr3ts3cr3ts3cr3ts3cr3t",
4
+ "github_api": {
5
+ "token": "t0k3n"
6
+ },
7
+ "github": {
8
+ "domain": null,
9
+ "app_id": 42,
10
+ "installation_id": 43,
11
+ "bot_login": "shipit[bot]",
12
+ "webhook_secret": null,
13
+ "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA7iUQC2uUq/gtQg0gxtyaccuicYgmq1LUr1mOWbmwM1Cv63+S\n73qo8h87FX+YyclY5fZF6SMXIys02JOkImGgbnvEOLcHnImCYrWs03msOzEIO/pG\nM0YedAPtQ2MEiLIu4y8htosVxeqfEOPiq9kQgFxNKyETzjdIA9q1md8sofuJUmPv\nibacW1PecuAMnn+P8qf0XIDp7uh6noB751KvhCaCNTAPtVE9NZ18OmNG9GOyX/pu\npQHIrPgTpTG6KlAe3r6LWvemzwsMtuRGU+K+KhK9dFIlSE+v9rA32KScO8efOh6s\nGu3rWorV4iDu14U62rzEfdzzc63YL94sUbZxbwIDAQABAoIBADLJ8r8MxZtbhYN1\nu0zOFZ45WL6v09dsBfITvnlCUeLPzYUDIzoxxcBFittN6C744x3ARS6wjimw+EdM\nTZALlCSb/sA9wMDQzt7wchhz9Zh2H5RzDu+2f54sjDh38KqancdT8PO2fAFGxX/b\nqicOVyeZB9gv6MJtJc20olBbuXAeBNfcDABF9oxF+0i+Ssg7B4VXiqgcjtGbr/Og\nqRll7AqyTArVx2xEcVfZxeZ4zGnigzcJq4te7yYpxzwk+RxblkPh54Yt4WxZ+8DI\nRsn3r6ajlpwzpwvsJFU2Txq7xBTzGQMFmy/Pnjk83kP2cogxB2+tRyjITGqTwD8b\ngg9PFCkCgYEA+7u8A0l0Cz6p0SI6c7ftVePVRiIhpawWN7og/wEmI6zUjm/3rA+R\nhrhaVKuOD8QF/HdDsqTck5gjGAjTmJz6r33/cl1Tz+pr62znsrB4r0yMKvQbKN81\nWGaWOsi2+ZXqLNv5h5wpUF0MTKlXHeKnwP5kuEvGwVn6WURFCh6PhLMCgYEA8i5e\nJjulJVGyd5HuoY3xyO7E6DjidsqRnVRq+hYpORjnHvTmSwe4+tH4ha2p9Kv2Y6k3\nC1NYY/fSMQoYCCRaYyJleI+la/9tsZqAmtms4ZB8KhFmPHf9fW75i6G0xKWyZ8K+\nE2Ft/UaEiM282593cguV6+Kt5uExnyPxLLK4FlUCgYEAwRJ/JGI8/7bjFkTTYheq\nj5q75BufhOrU6471acAe2XPgXxLfefdC3Xodxh0CS3NESBvNL4Ikr4sbN37lk4Kq\n/th7iOKtuqUIeru/hZy2I3VpeDRbdGCmEJQ2GwYA2LKztg5Nd0Y9paaIHXAwIfrK\nQUqcQ4HTAk8ZpUeoUBeaaeMCgYANLmbjb9WiPVsYVPIHCwHA7PX8qbPxwT7BsGmO\nKQyfVfKmZa/vH4F67Vi4deZNMdrcO8aKMEQcVM2065a5QrlEsgeR00eupB1lUEJ1\nqylUsZeAdqf43JMIc7TTW77KATa/nQLZbTEeWus1wvTngztuEqFbUGAks9cOkVc8\nFpIcbQKBgQDVIL8gPLmn0f+4oLF8MBC+oxtKpz14X5iJ1saGFkzW5I+nIEskpS0S\nqtirnTCnJFGdCrFwctnxiuiCmyGwpBYdjIfHyvYAHnqAtMnESzCUyeSFZiquVW5W\nMvbMmDPoV27XOHU9kIq6NXtfrkpufiyo6/VEYWozXalxKLNuqLYfPQ==\n-----END RSA PRIVATE KEY-----\n",
14
+ "oauth": {
15
+ "id": "Iv1.bf2c2c45b449bfd9",
16
+ "secret": "ef694cd6e45223075d78d138ef014049052665f1",
17
+ "teams": null
18
+ }
19
+ },
20
+ "redis_url": "redis://127.0.0.1:6379/7"
21
+ }
@@ -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: 2021_11_03_154121) do
13
+ ActiveRecord::Schema.define(version: 2023_07_03_181143) do
14
14
 
15
15
  create_table "api_clients", force: :cascade do |t|
16
16
  t.text "permissions", limit: 65535
@@ -42,7 +42,7 @@ ActiveRecord::Schema.define(version: 2021_11_03_154121) do
42
42
  create_table "commit_deployment_statuses", force: :cascade do |t|
43
43
  t.integer "commit_deployment_id"
44
44
  t.string "status"
45
- t.integer "github_id"
45
+ t.bigint "github_id"
46
46
  t.string "api_url"
47
47
  t.datetime "created_at", null: false
48
48
  t.datetime "updated_at", null: false
@@ -8,3 +8,16 @@ module ApiHelper
8
8
  request.headers['Authorization'] = "Basic #{Base64.encode64(client.authentication_token)}"
9
9
  end
10
10
  end
11
+
12
+ module Shipit
13
+ class ApiControllerTestCase < ActionController::TestCase
14
+ private
15
+
16
+ def process(_action, **kwargs)
17
+ if kwargs[:method] != "GET"
18
+ kwargs[:as] ||= :json
19
+ end
20
+ super
21
+ end
22
+ end
23
+ end
@@ -15,7 +15,6 @@ module Shipit
15
15
  @author.github_api.class.any_instance.expects(:create_deployment_status).with(
16
16
  @deployment.api_url,
17
17
  'in_progress',
18
- accept: "application/vnd.github.flash-preview+json",
19
18
  target_url: "http://shipit.com/shopify/shipit-engine/production/deploys/#{@task.id}",
20
19
  description: "walrus triggered the deploy of shopify/shipit-engine/production to #{@deployment.short_sha}",
21
20
  environment_url: "https://shipit.shopify.com",
@@ -243,7 +243,10 @@ module Shipit
243
243
  end
244
244
 
245
245
  test "status transitions emit hooks" do
246
- job = assert_enqueued_with(job: EmitEventJob) do
246
+ expected_args = ->(job_args) do
247
+ job_args.first[:event] == 'merge'
248
+ end
249
+ job = assert_enqueued_with(job: EmitEventJob, args: expected_args) do
247
250
  @pr.reject!('merge_conflict')
248
251
  end
249
252
  params = job.arguments.first
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  require 'securerandom'
4
4
 
5
5
  module Shipit
6
- class StacksTest < ActiveSupport::TestCase
6
+ class StackTest < ActiveSupport::TestCase
7
7
  def setup
8
8
  @stack = shipit_stacks(:shipit)
9
9
  @expected_base_path = Rails.root.join('data', 'stacks', @stack.to_param).to_s
@@ -278,6 +278,36 @@ module Shipit
278
278
  end
279
279
  end
280
280
 
281
+ test "#active_task? is false if stack has a concurrent deploy in active state" do
282
+ @stack.trigger_deploy(shipit_commits(:third), AnonymousUser.new, force: true)
283
+ refute @stack.active_task?
284
+ end
285
+
286
+ test "#occupied? is false if stack has no deploy in either pending or running state" do
287
+ @stack.deploys.active.destroy_all
288
+ refute @stack.occupied?
289
+ end
290
+
291
+ test "#occupied? is false if stack has no deploy at all" do
292
+ @stack.deploys.destroy_all
293
+ refute @stack.occupied?
294
+ end
295
+
296
+ test "occupied? is true if stack has a concurrent deploy in active state" do
297
+ @stack.trigger_deploy(shipit_commits(:third), AnonymousUser.new, force: true)
298
+ assert @stack.occupied?
299
+ end
300
+
301
+ test "occupied? is true if stack has a deploy in pending state" do
302
+ @stack.trigger_deploy(shipit_commits(:third), AnonymousUser.new)
303
+ assert @stack.occupied?
304
+ end
305
+
306
+ test "#occupied? is true if a rollback is ongoing" do
307
+ shipit_deploys(:shipit_complete).trigger_rollback(AnonymousUser.new)
308
+ assert @stack.occupied?
309
+ end
310
+
281
311
  test "#deployable? returns true if the stack is not locked, not awaiting provision, and is not deploying" do
282
312
  @stack.deploys.destroy_all
283
313
  @stack.update!(lock_reason: nil, awaiting_provision: false)
@@ -674,12 +704,12 @@ module Shipit
674
704
  assert_equal shipit_commits(:fifth), @stack.next_commit_to_deploy
675
705
  end
676
706
 
677
- test "#next_commit_to_deploy respects the deploy.max_commits directive" do
707
+ test "#next_commit_to_deploy respects the deploy.max_commits directive given the commit is deployable" do
678
708
  @stack.tasks.destroy_all
679
709
 
680
- fifth_commit = shipit_commits(:third)
681
- fifth_commit.statuses.create!(stack_id: @stack.id, state: 'success', context: 'ci/travis')
682
- assert_predicate fifth_commit, :deployable?
710
+ third_commit = shipit_commits(:third)
711
+ third_commit.statuses.create!(stack_id: @stack.id, state: 'success', context: 'ci/travis')
712
+ assert_predicate third_commit, :deployable?
683
713
 
684
714
  assert_equal shipit_commits(:third), @stack.next_commit_to_deploy
685
715
 
@@ -687,6 +717,19 @@ module Shipit
687
717
  assert_equal shipit_commits(:third), @stack.next_commit_to_deploy
688
718
  end
689
719
 
720
+ test "#next_commit_to_deploy deploys the first deployable commit when deploy.max_commits directive fails to find a deployable commit" do
721
+ @stack.tasks.destroy_all
722
+
723
+ third_commit = shipit_commits(:third)
724
+ third_commit.statuses.create!(stack_id: @stack.id, state: 'success', context: 'ci/travis')
725
+ assert_predicate third_commit, :deployable?
726
+
727
+ assert_equal shipit_commits(:third), @stack.next_commit_to_deploy
728
+
729
+ @stack.expects(:maximum_commits_per_deploy).returns(1).at_least_once
730
+ assert_equal shipit_commits(:third), @stack.next_commit_to_deploy
731
+ end
732
+
690
733
  test "setting #lock_reason also sets #locked_since" do
691
734
  assert_predicate @stack.locked_since, :nil?
692
735
 
@@ -203,6 +203,14 @@ module Shipit
203
203
  assert_equal 'george@cyclim.se', user.email
204
204
  end
205
205
 
206
+ test "#refresh_from_github! logs deleted users" do
207
+ Shipit.github.api.expects(:user).with(@user.github_id).raises(Octokit::Forbidden)
208
+
209
+ Rails.logger.expects(:info).with("User #{@user.name}, github_id #{@user.github_id} has forbidden access to their GitHub, likely deleted.")
210
+
211
+ @user.refresh_from_github!
212
+ end
213
+
206
214
  test "#github_api uses the user's access token" do
207
215
  assert_equal @user.github_access_token, @user.github_api.access_token
208
216
  end
data/test/test_helper.rb CHANGED
@@ -23,7 +23,7 @@ require 'spy/integration'
23
23
 
24
24
  # Load fixtures from the engine
25
25
  if ActiveSupport::TestCase.respond_to?(:fixture_path=)
26
- ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
26
+ ActiveSupport::TestCase.fixture_paths << File.expand_path("../fixtures", __FILE__)
27
27
  ActiveSupport::TestCase.fixtures(:all)
28
28
  end
29
29
 
@@ -71,7 +71,7 @@ module ActiveSupport
71
71
  end
72
72
  end
73
73
 
74
- ActiveRecord::Migration.check_pending!
74
+ ActiveRecord::Migration.check_all_pending!
75
75
 
76
76
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
77
77
  #
@@ -21,6 +21,100 @@ module Shipit
21
21
  StackCommands.stubs(git_version: Gem::Version.new('1.8.4.3'))
22
22
  end
23
23
 
24
+ test "#fetch_commit calls git fetch if repository cache already exist" do
25
+ @stack.git_path.stubs(:exist?).returns(true)
26
+ @stack.git_path.stubs(:empty?).returns(false)
27
+
28
+ command = @commands.fetch_commit(@deploy.until_commit)
29
+
30
+ assert_equal %W(git fetch origin --quiet --tags #{@deploy.until_commit.sha}), command.args
31
+ end
32
+
33
+ test "#fetch_commit calls git fetch in git_path directory if repository cache already exist" do
34
+ @stack.git_path.stubs(:exist?).returns(true)
35
+ @stack.git_path.stubs(:empty?).returns(false)
36
+
37
+ command = @commands.fetch_commit(@deploy.until_commit)
38
+
39
+ assert_equal @stack.git_path.to_s, command.chdir
40
+ end
41
+
42
+ test "#fetch_commit calls git clone if repository cache do not exist" do
43
+ @stack.git_path.stubs(:exist?).returns(false)
44
+
45
+ command = @commands.fetch_commit(@deploy.until_commit)
46
+
47
+ expected = %W(git clone --quiet --single-branch --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
48
+ assert_equal expected, command.args.map(&:to_s)
49
+ end
50
+
51
+ test "#fetch_commit calls git clone if repository cache is empty" do
52
+ @stack.git_path.stubs(:exist?).returns(true)
53
+ @stack.git_path.stubs(:empty?).returns(true)
54
+
55
+ command = @commands.fetch_commit(@deploy.until_commit)
56
+
57
+ expected = %W(git clone --quiet --single-branch --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
58
+ assert_equal expected, command.args
59
+ end
60
+
61
+ test "#fetch_commit calls git clone if repository cache corrupt" do
62
+ @stack.git_path.stubs(:exist?).returns(true)
63
+ @stack.git_path.stubs(:empty?).returns(false)
64
+ StackCommands.any_instance.expects(:git_cmd_succeeds?)
65
+ .with(@stack.git_path)
66
+ .returns(false)
67
+
68
+ command = @commands.fetch_commit(@deploy.until_commit)
69
+
70
+ expected = %W(git clone --quiet --single-branch --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
71
+ assert_equal expected, command.args
72
+ end
73
+
74
+ test "#fetch_commit clears a corrupted git stash before cloning" do
75
+ @stack.expects(:clear_git_cache!)
76
+ @stack.git_path.stubs(:exist?).returns(true)
77
+ @stack.git_path.stubs(:empty?).returns(false)
78
+ StackCommands.any_instance.expects(:git_cmd_succeeds?)
79
+ .with(@stack.git_path)
80
+ .returns(false)
81
+
82
+ command = @commands.fetch_commit(@deploy.until_commit)
83
+
84
+ expected = %W(git clone --quiet --single-branch --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
85
+ assert_equal expected, command.args
86
+ end
87
+
88
+ test "#fetch_commit does not use --single-branch if git is outdated" do
89
+ @stack.git_path.stubs(:exist?).returns(false)
90
+ StackCommands.stubs(git_version: Gem::Version.new('1.7.2.30'))
91
+
92
+ command = @commands.fetch_commit(@deploy.until_commit)
93
+
94
+ expected = %W(git clone --quiet --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
95
+ assert_equal expected, command.args.map(&:to_s)
96
+ end
97
+
98
+ test "#fetch_commit calls git fetch in base_path directory if repository cache do not exist" do
99
+ @stack.git_path.stubs(:exist?).returns(false)
100
+
101
+ command = @commands.fetch_commit(@deploy.until_commit)
102
+
103
+ assert_equal @stack.deploys_path.to_s, command.chdir
104
+ end
105
+
106
+ test "#fetch_commit merges Shipit.env in ENVIRONMENT" do
107
+ Shipit.stubs(:env).returns("SPECIFIC_CONFIG" => 5)
108
+ command = @commands.fetch_commit(@deploy.until_commit)
109
+ assert_equal '5', command.env["SPECIFIC_CONFIG"]
110
+ end
111
+
112
+ test "#env uses the correct Github token for a stack" do
113
+ Shipit.github(organization: 'shopify').stubs(:token).returns('aS3cr3Tt0kEn')
114
+ command = @commands.fetch_commit(@deploy.until_commit)
115
+ assert_equal 'aS3cr3Tt0kEn', command.env["GITHUB_TOKEN"]
116
+ end
117
+
24
118
  test "#fetch calls git fetch if repository cache already exist" do
25
119
  @stack.git_path.stubs(:exist?).returns(true)
26
120
  @stack.git_path.stubs(:empty?).returns(false)
@@ -109,12 +203,6 @@ module Shipit
109
203
  assert_equal '5', command.env["SPECIFIC_CONFIG"]
110
204
  end
111
205
 
112
- test "#env uses the correct Github token for a stack" do
113
- Shipit.github(organization: 'shopify').stubs(:token).returns('aS3cr3Tt0kEn')
114
- command = @commands.fetch
115
- assert_equal 'aS3cr3Tt0kEn', command.env["GITHUB_TOKEN"]
116
- end
117
-
118
206
  test "#clone clones the repository cache into the working directory" do
119
207
  commands = @commands.clone
120
208
  assert_equal 2, commands.size
@@ -202,7 +202,7 @@ module Shipit
202
202
  end
203
203
 
204
204
  def default_config
205
- Rails.application.secrets.github.deep_dup
205
+ Rails.application.credentials.github.deep_dup
206
206
  end
207
207
  end
208
208
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shipit-engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.37.0
4
+ version: 0.39.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-10 00:00:00.000000000 Z
11
+ date: 2024-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_model_serializers
@@ -156,14 +156,14 @@ dependencies:
156
156
  requirements:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: '4.20'
159
+ version: 5.6.0
160
160
  type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: '4.20'
166
+ version: 5.6.0
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: omniauth-github
169
169
  requirement: !ruby/object:Gem::Requirement
@@ -198,14 +198,14 @@ dependencies:
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: 7.0.0
201
+ version: 7.1.1
202
202
  type: :runtime
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: 7.0.0
208
+ version: 7.1.1
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: rails-timeago
211
211
  requirement: !ruby/object:Gem::Requirement
@@ -507,6 +507,7 @@ files:
507
507
  - app/controllers/shipit/status_controller.rb
508
508
  - app/controllers/shipit/tasks_controller.rb
509
509
  - app/controllers/shipit/webhooks_controller.rb
510
+ - app/helpers/shipit/api_clients_helper.rb
510
511
  - app/helpers/shipit/chunks_helper.rb
511
512
  - app/helpers/shipit/deploys_helper.rb
512
513
  - app/helpers/shipit/github_url_helper.rb
@@ -771,6 +772,7 @@ files:
771
772
  - db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb
772
773
  - db/migrate/20210823075617_change_check_runs_github_updated_at_default.rb
773
774
  - db/migrate/20211103154121_increase_github_team_slug_size.rb
775
+ - db/migrate/20230703181143_change_commit_deployment_statuses_github_id_to_big_int.rb
774
776
  - lib/shipit-engine.rb
775
777
  - lib/shipit.rb
776
778
  - lib/shipit/cast_value.rb
@@ -876,6 +878,8 @@ files:
876
878
  - test/dummy/config/initializers/wrap_parameters.rb
877
879
  - test/dummy/config/locales/en.yml
878
880
  - test/dummy/config/routes.rb
881
+ - test/dummy/config/secrets.development.json
882
+ - test/dummy/config/secrets.test.json
879
883
  - test/dummy/config/secrets.yml
880
884
  - test/dummy/config/secrets_double_github_app.yml
881
885
  - test/dummy/db/schema.rb
@@ -972,7 +976,7 @@ files:
972
976
  - test/models/shipit/review_stack_provision_status_test.rb
973
977
  - test/models/shipit/review_stack_provisioning_queue_test.rb
974
978
  - test/models/shipit/review_stack_test.rb
975
- - test/models/shipit/stacks_test.rb
979
+ - test/models/shipit/stack_test.rb
976
980
  - test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb
977
981
  - test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb
978
982
  - test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb
@@ -1039,7 +1043,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1039
1043
  - !ruby/object:Gem::Version
1040
1044
  version: '0'
1041
1045
  requirements: []
1042
- rubygems_version: 3.3.3
1046
+ rubygems_version: 3.5.7
1043
1047
  signing_key:
1044
1048
  specification_version: 4
1045
1049
  summary: Application deployment software
@@ -1102,6 +1106,8 @@ test_files:
1102
1106
  - test/dummy/config/initializers/wrap_parameters.rb
1103
1107
  - test/dummy/config/locales/en.yml
1104
1108
  - test/dummy/config/routes.rb
1109
+ - test/dummy/config/secrets.development.json
1110
+ - test/dummy/config/secrets.test.json
1105
1111
  - test/dummy/config/secrets.yml
1106
1112
  - test/dummy/config/secrets_double_github_app.yml
1107
1113
  - test/dummy/config.ru
@@ -1199,7 +1205,7 @@ test_files:
1199
1205
  - test/models/shipit/review_stack_provision_status_test.rb
1200
1206
  - test/models/shipit/review_stack_provisioning_queue_test.rb
1201
1207
  - test/models/shipit/review_stack_test.rb
1202
- - test/models/shipit/stacks_test.rb
1208
+ - test/models/shipit/stack_test.rb
1203
1209
  - test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb
1204
1210
  - test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb
1205
1211
  - test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb