2020-05-25 11:07:58 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Ci
|
|
|
|
class CreateWebIdeTerminalService < ::BaseService
|
|
|
|
include ::Gitlab::Utils::StrongMemoize
|
|
|
|
|
|
|
|
TerminalCreationError = Class.new(StandardError)
|
|
|
|
|
2021-01-07 16:10:18 -05:00
|
|
|
TERMINAL_NAME = 'terminal'
|
2020-05-25 11:07:58 -04:00
|
|
|
|
|
|
|
attr_reader :terminal
|
|
|
|
|
|
|
|
def execute
|
|
|
|
check_access!
|
|
|
|
validate_params!
|
|
|
|
load_terminal_config!
|
|
|
|
|
|
|
|
pipeline = create_pipeline!
|
|
|
|
success(pipeline: pipeline)
|
|
|
|
rescue TerminalCreationError => e
|
|
|
|
error(e.message)
|
|
|
|
rescue ActiveRecord::RecordInvalid => e
|
|
|
|
error("Failed to persist the pipeline: #{e.message}")
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def create_pipeline!
|
|
|
|
build_pipeline.tap do |pipeline|
|
|
|
|
pipeline.stages << terminal_stage_seed(pipeline).to_resource
|
2021-05-05 08:10:33 -04:00
|
|
|
|
2021-05-10 11:10:24 -04:00
|
|
|
# Project iid must be called outside a transaction, so we ensure it is set here
|
|
|
|
# otherwise it may be set within the save! which it will lock the InternalId row for the whole transaction
|
|
|
|
pipeline.ensure_project_iid!
|
2021-05-05 08:10:33 -04:00
|
|
|
|
2020-05-25 11:07:58 -04:00
|
|
|
pipeline.save!
|
|
|
|
|
|
|
|
Ci::ProcessPipelineService
|
|
|
|
.new(pipeline)
|
2020-08-13 11:10:03 -04:00
|
|
|
.execute
|
2020-05-25 11:07:58 -04:00
|
|
|
|
|
|
|
pipeline_created_counter.increment(source: :webide)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_pipeline
|
|
|
|
Ci::Pipeline.new(
|
|
|
|
project: project,
|
|
|
|
user: current_user,
|
|
|
|
source: :webide,
|
|
|
|
config_source: :webide_source,
|
|
|
|
ref: ref,
|
|
|
|
sha: sha,
|
|
|
|
tag: false,
|
|
|
|
before_sha: Gitlab::Git::BLANK_SHA
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
def terminal_stage_seed(pipeline)
|
|
|
|
attributes = {
|
|
|
|
name: TERMINAL_NAME,
|
|
|
|
index: 0,
|
|
|
|
builds: [terminal_build_seed]
|
|
|
|
}
|
|
|
|
|
2021-03-25 08:09:19 -04:00
|
|
|
seed_context = Gitlab::Ci::Pipeline::Seed::Context.new(pipeline)
|
|
|
|
Gitlab::Ci::Pipeline::Seed::Stage.new(seed_context, attributes, [])
|
2020-05-25 11:07:58 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def terminal_build_seed
|
|
|
|
terminal.merge(
|
|
|
|
name: TERMINAL_NAME,
|
|
|
|
stage: TERMINAL_NAME,
|
|
|
|
user: current_user,
|
|
|
|
scheduling_type: :stage)
|
|
|
|
end
|
|
|
|
|
|
|
|
def load_terminal_config!
|
2020-09-15 23:09:23 -04:00
|
|
|
result = ::Ide::TerminalConfigService.new(project, current_user, sha: sha).execute
|
2020-05-25 11:07:58 -04:00
|
|
|
raise TerminalCreationError, result[:message] if result[:status] != :success
|
|
|
|
|
|
|
|
@terminal = result[:terminal]
|
|
|
|
raise TerminalCreationError, 'Terminal is not configured' unless terminal
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_params!
|
|
|
|
unless sha
|
|
|
|
raise TerminalCreationError, 'Ref does not exist'
|
|
|
|
end
|
|
|
|
|
|
|
|
unless branch_exists?
|
|
|
|
raise TerminalCreationError, 'Ref needs to be a branch'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_access!
|
|
|
|
unless can?(current_user, :create_web_ide_terminal, project)
|
|
|
|
raise TerminalCreationError, 'Insufficient permissions to create a terminal'
|
|
|
|
end
|
|
|
|
|
|
|
|
if terminal_active?
|
|
|
|
raise TerminalCreationError, 'There is already a terminal running'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def pipeline_created_counter
|
|
|
|
@pipeline_created_counter ||= Gitlab::Metrics
|
|
|
|
.counter(:pipelines_created_total, "Counter of pipelines created")
|
|
|
|
end
|
|
|
|
|
|
|
|
def terminal_active?
|
|
|
|
project.active_webide_pipelines(user: current_user).exists?
|
|
|
|
end
|
|
|
|
|
|
|
|
def ref
|
|
|
|
strong_memoize(:ref) do
|
|
|
|
Gitlab::Git.ref_name(params[:ref])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def branch_exists?
|
|
|
|
project.repository.branch_exists?(ref)
|
|
|
|
end
|
|
|
|
|
|
|
|
def sha
|
|
|
|
project.commit(params[:ref]).try(:id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|