From c2c77ea26069b6d3390b5fd60f8464efadc9c485 Mon Sep 17 00:00:00 2001 From: Kartiki Sharma Date: Tue, 19 Mar 2024 11:19:39 -0400 Subject: [PATCH] Stack: update `build_deploy` to pass `allow_concurrency` Add unit tests --- CHANGELOG.md | 2 ++ README.md | 5 ++++ .../shipit/api/deploys_controller.rb | 6 ++++- app/models/shipit/stack.rb | 4 ++-- .../api/deploys_controller_test.rb | 23 +++++++++++++++++++ 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba8a009f4..0a5c3c017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ * Migrate from legacy Rails secrets to credentials (#1326) * Rails secrets were [deprecated in Rails 7.1](https://github.com/rails/rails/pull/48472) * [Guide on credentials](https://guides.rubyonrails.org/security.html#custom-credentials) +* For deployments, `allow_concurrency` defaults to the same value as `force`. If wanted, it can be set separately by passing the intended value for `allow_concurrency` to `build_deploy` method + # 0.39.0 diff --git a/README.md b/README.md index e8a6f17f1..a48fa65e7 100644 --- a/README.md +++ b/README.md @@ -357,6 +357,11 @@ For example: fetch: curl --silent https://app.example.com/services/ping/version ``` + +**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), +whose `allow_concurrency` keyword argument defaults to `force`, where `force` is true when emergency mode is enabled. +If you'd like to separate these two from one another, override this method as desired in your service. +

Kubernetes

**kubernetes** allows to specify a Kubernetes namespace and context to deploy to. diff --git a/app/controllers/shipit/api/deploys_controller.rb b/app/controllers/shipit/api/deploys_controller.rb index d80dedbfb..3ccb3f077 100644 --- a/app/controllers/shipit/api/deploys_controller.rb +++ b/app/controllers/shipit/api/deploys_controller.rb @@ -11,6 +11,7 @@ def index params do requires :sha, String, length: { in: 6..40 } accepts :force, Boolean, default: false + accepts :allow_concurrency, Boolean accepts :require_ci, Boolean, default: false accepts :env, Hash, default: {} end @@ -18,7 +19,10 @@ def create commit = stack.commits.by_sha(params.sha) || param_error!(:sha, 'Unknown revision') param_error!(:force, "Can't deploy a locked stack") if !params.force && stack.locked? param_error!(:require_ci, "Commit is not deployable") if params.require_ci && !commit.deployable? - deploy = stack.trigger_deploy(commit, current_user, env: params.env, force: params.force) + + allow_concurrency = params.allow_concurrency.nil? ? params.force : params.allow_concurrency + deploy = stack.trigger_deploy(commit, current_user, env: params.env, force: params.force, + allow_concurrency: allow_concurrency) render_resource(deploy, status: :accepted) end end diff --git a/app/models/shipit/stack.rb b/app/models/shipit/stack.rb index 4f2642f89..23767f254 100644 --- a/app/models/shipit/stack.rb +++ b/app/models/shipit/stack.rb @@ -150,14 +150,14 @@ def trigger_task(definition_id, user, env: nil, force: false) task end - def build_deploy(until_commit, user, env: nil, force: false) + def build_deploy(until_commit, user, env: nil, force: false, allow_concurrency: force) since_commit = last_deployed_commit.presence || commits.first deploys.build( user_id: user.id, until_commit: until_commit, since_commit: since_commit, env: filter_deploy_envs(env&.to_h || {}), - allow_concurrency: force, + allow_concurrency: allow_concurrency, ignored_safeties: force || !until_commit.deployable?, max_retries: retries_on_deploy, ) diff --git a/test/controllers/api/deploys_controller_test.rb b/test/controllers/api/deploys_controller_test.rb index 7a044b8ff..c7ebbf02a 100644 --- a/test/controllers/api/deploys_controller_test.rb +++ b/test/controllers/api/deploys_controller_test.rb @@ -120,6 +120,29 @@ class DeploysControllerTest < ApiControllerTestCase assert_response :accepted assert_json 'status', 'pending' end + + test "#create uses allow_concurrency param when provided" do + @stack.update!(lock_reason: 'Something broken') + + assert_difference -> { @stack.deploys.count }, 1 do + post :create, params: { stack_id: @stack.to_param, sha: @commit.sha, force: 'true', allow_concurrency: 'false' } + end + assert_response :accepted + assert_json 'status', 'pending' + refute @stack.deploys.last.allow_concurrency + end + + test "#create defaults allow_concurrency to force param when not provided" do + @stack.update!(lock_reason: 'Something broken') + expected_force = true + + assert_difference -> { @stack.deploys.count }, 1 do + post :create, params: { stack_id: @stack.to_param, sha: @commit.sha, force: expected_force } + end + assert_response :accepted + assert_json 'status', 'pending' + assert_equal expected_force, @stack.deploys.last.allow_concurrency + end end end end