require "option_parser"
require "./project"
require "./pipeline"
require "./stage"
require "./command"
require "./logger"
require "./utils"
module Gitfoss::Ci::Runner
VERSION = "0.1.0"
DOCKER_API_VERSION = "v1.47"
def self.run()
options = {} of Symbol => String
OptionParser.parse do |parser|
parser.banner = "Usage: run_pipeline.cr [options] pipeline.yml"
parser.on("-d", "--docker-host HOST", "Docker host (optional)") do |h|
options[:docker_host] = h
end
parser.on("-f", "--file FILE", "Path to the YAML file") do |f|
options[:yaml_file] = f
end
parser.on("-h", "--help", "Show this help") do
puts parser
exit 0
end
parser.invalid_option do |flag|
on_failed_pipeline
err_pipe "ERROR: #{flag} is not a valid option."
err_pipe parser.to_s
exit 1
end
end
yaml_path = options[:yaml_file]? || ARGV[0]?
unless yaml_path
on_failed_pipeline
err_pipe "No YAML file specified"
exit 1
end
unless File.exists?(yaml_path.not_nil!)
on_failed_pipeline
err_pipe "File not found: #{yaml_path}"
exit 1
end
yaml = load_yaml(yaml_path)
docker =
if options[:docker_host]?
Docker::Client.new(options[:docker_host], DOCKER_API_VERSION)
else
Docker::Client.new(nil, DOCKER_API_VERSION)
end
project = Project.new(orgSlug: "ethicdevs", repoSlug: "gitfoss")
pipeline = Pipeline.new(id: "pipeline-1")
stages_node = yaml["stages"]
unless stages_node
on_failed_pipeline
err_pipe "YAML missing 'stages' top-level key"
exit 1
end
stages_node.as_a.each do |stage_node|
stage_name = stage_node["name"].as_s
log_pipe "Running stage: #{stage_name}"
stage = Stage.new(stage_name)
if stage_node["steps"]?
stage_node["steps"].as_a.each do |step_node|
cmd_node =
if step_node.is_a?(YAML::Any) && step_node["image"]
step_node
else
YAML.parse({
"image" => stage_node["image"],
"workdir" => stage_node["workdir"]? || "",
"shell" => stage_node["shell"]? || "sh",
"env" => stage_node["env"]? || {} of String => String,
"commands" => [step_node]
}.to_yaml)
end
begin
command_name = "#{project.to_s}/#{pipeline.id}/stage_#{stage_name}_#{Time.utc.to_unix}".gsub('/', '_')
command = map_to_command(command_name, cmd_node)
exit_code = command.run(docker, project, pipeline, stage)
if exit_code != 0
on_failed_pipeline
else
on_passed_pipeline
end
rescue ex
on_failed_pipeline
err_pipe "Stage #{stage_name} step failed", ex
exit 1
end
end
else
begin
command_name = "#{project.to_s}/#{pipeline.id}/stage_#{stage_name}_#{Time.utc.to_unix}".gsub('/', '_')
command = map_to_command(command_name, stage_node)
exit_code = command.run(docker, project, pipeline, stage)
if exit_code != 0
on_failed_pipeline
else
on_passed_pipeline
end
rescue ex
on_failed_pipeline
err_pipe "Stage #{stage_name} failed", ex
exit 1
end
end
end
end
end
Gitfoss::Ci::Runner.run