From 02004bace6f10d2b4e4ff3d5d582a76d24e201e8 Mon Sep 17 00:00:00 2001 From: Michael Grosser Date: Mon, 8 Oct 2018 19:34:10 -0700 Subject: [PATCH] allow falling back to full checkout for stages that do weird stuff followup to https://github.com/zendesk/samson/pull/2973 which broke stages that switch branches (they should not do that ever ...) or try to create tags --- app/controllers/stages_controller.rb | 1 + app/models/git_repository.rb | 17 ++++++++--- app/models/job_execution.rb | 1 + app/views/stages/_fields.html.erb | 2 ++ ...81009022203_add_full_checkout_to_stages.rb | 6 ++++ db/schema.rb | 3 +- test/models/git_repository_test.rb | 30 +++++++++++-------- test/models/job_execution_test.rb | 6 ++++ 8 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 db/migrate/20181009022203_add_full_checkout_to_stages.rb diff --git a/app/controllers/stages_controller.rb b/app/controllers/stages_controller.rb index 770ffe1f13..b667595a9e 100644 --- a/app/controllers/stages_controller.rb +++ b/app/controllers/stages_controller.rb @@ -142,6 +142,7 @@ def stage_permitted_params :production, :run_in_parallel, :static_emails_on_automated_deploy_failure, + :full_checkout, { deploy_group_ids: [], command_ids: [] diff --git a/app/models/git_repository.rb b/app/models/git_repository.rb index 099b68160b..dfd8c96ea9 100644 --- a/app/models/git_repository.rb +++ b/app/models/git_repository.rb @@ -5,6 +5,7 @@ class GitRepository extend ::Samson::PerformanceTracer::Tracers attr_accessor :executor # others set this to listen in on commands being executed + attr_accessor :full_checkout # The directory in which repositories should be cached. # TODO: find out and comment why this needs to be settable or make read-only self. method @@ -143,10 +144,18 @@ def sha_exist?(sha) end def checkout(git_reference, work_dir) - executor.execute( - "cd #{repo_cache_dir}", - "git worktree add #{work_dir.shellescape} #{git_reference.shellescape} --force" - ) + if full_checkout + executor.execute( + "git clone #{repo_cache_dir} #{work_dir.shellescape}", + "cd #{work_dir.shellescape}", + "git checkout --quiet #{git_reference.shellescape}" + ) + else + executor.execute( + "cd #{repo_cache_dir}", + "git worktree add #{work_dir.shellescape} #{git_reference.shellescape} --force" + ) + end end def checkout_submodules(pwd) diff --git a/app/models/job_execution.rb b/app/models/job_execution.rb index 604663f8c3..19c5f36fef 100644 --- a/app/models/job_execution.rb +++ b/app/models/job_execution.rb @@ -27,6 +27,7 @@ def initialize(reference, job, env: {}, output: OutputBuffer.new, &block) @repository = @job.project.repository @repository.executor = @executor + @repository.full_checkout = true if stage&.full_checkout on_finish do Rails.logger.info("Calling finish callback for Job Execution #{id}") diff --git a/app/views/stages/_fields.html.erb b/app/views/stages/_fields.html.erb index 182e3ccb4a..8d379bd304 100644 --- a/app/views/stages/_fields.html.erb +++ b/app/views/stages/_fields.html.erb @@ -36,6 +36,8 @@ <%= form.input :no_reference_selection, as: :check_box, label: "Disable reference selection", help: no_ref_label %> + <%= form.input :full_checkout, as: :check_box, label: "Use a full checkout", help: "Samson usually uses a worktree which is a lot faster, pick this option if you want to switch branches during deploy." %> + <% if interval = Samson::Periodical.interval(:periodical_deploy) %> <%= form.input :periodical_deploy, as: :check_box, help: "Deploy every #{distance_of_time_in_words(interval)} if last deploy succeeded, enable automated deploy failure email to be alerted. " %> <% end %> diff --git a/db/migrate/20181009022203_add_full_checkout_to_stages.rb b/db/migrate/20181009022203_add_full_checkout_to_stages.rb new file mode 100644 index 0000000000..1e90a33336 --- /dev/null +++ b/db/migrate/20181009022203_add_full_checkout_to_stages.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true +class AddFullCheckoutToStages < ActiveRecord::Migration[5.2] + def change + add_column :stages, :full_checkout, :boolean, default: false, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index cab6a59a17..3b4e437736 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_09_21_170100) do +ActiveRecord::Schema.define(version: 2018_10_09_022203) do create_table "audits" do |t| t.integer "auditable_id", null: false @@ -531,6 +531,7 @@ t.float "average_deploy_time" t.string "prerequisite_stage_ids" t.string "default_reference" + t.boolean "full_checkout", default: false, null: false t.index ["project_id", "permalink"], name: "index_stages_on_project_id_and_permalink", unique: true, length: { permalink: 191 } t.index ["template_stage_id"], name: "index_stages_on_template_stage_id" end diff --git a/test/models/git_repository_test.rb b/test/models/git_repository_test.rb index dd8c58c17b..6b96c333c6 100644 --- a/test/models/git_repository_test.rb +++ b/test/models/git_repository_test.rb @@ -213,19 +213,25 @@ def call describe "#checkout_workspace" do before { create_repo_with_an_additional_branch } - it 'creates a repository' do - Dir.mktmpdir do |temp_dir| - assert repository.checkout_workspace(temp_dir, 'test_user/test_branch') - Dir.chdir(temp_dir) { current_branch.must_equal('test_user/test_branch') } - end - end + [true, false].each do |full_checkout| + describe "with full_checkout #{full_checkout}" do + before { repository.full_checkout = full_checkout } + + it 'creates a repository' do + Dir.mktmpdir do |temp_dir| + assert repository.checkout_workspace(temp_dir, 'test_user/test_branch') + Dir.chdir(temp_dir) { current_branch.must_equal('test_user/test_branch') } + end + end - it 'checks out submodules' do - add_submodule_to_repo - Dir.mktmpdir do |temp_dir| - assert repository.checkout_workspace(temp_dir, 'master') - Dir.exist?("#{temp_dir}/submodule").must_equal true - File.read("#{temp_dir}/submodule/bar").must_equal "banana\n" + it 'checks out submodules' do + add_submodule_to_repo + Dir.mktmpdir do |temp_dir| + assert repository.checkout_workspace(temp_dir, 'master') + Dir.exist?("#{temp_dir}/submodule").must_equal true + File.read("#{temp_dir}/submodule/bar").must_equal "banana\n" + end + end end end end diff --git a/test/models/job_execution_test.rb b/test/models/job_execution_test.rb index e937f54f45..b0afecf191 100644 --- a/test/models/job_execution_test.rb +++ b/test/models/job_execution_test.rb @@ -66,6 +66,12 @@ def last_line_of_output assert_equal '[04:05:06] monkey', last_line_of_output end + it 'can do a full checkout when requested' do + stage.update_column(:full_checkout, true) + execute_job 'master' + job.output.to_s.wont_include 'worktree' + end + it 'does not fail with nil ENV vars' do User.any_instance.expects(:name).at_least_once.returns(nil) execution.send(:run)