class Concourse
def self.default_execute_args(task)
def self.default_execute_args(task) args = [] task["config"]["inputs"].each do |input| args << "--input=#{input["name"]}=." end args.join(" ") end
def self.production_rubies
def self.production_rubies RUBIES[:mri].reject { |r| r =~ /rc/ } end
def self.rc_rubies
def self.rc_rubies RUBIES[:mri].select { |r| r =~ /rc/ } end
def self.url_for(fly_target)
def self.url_for(fly_target) matching_line = `fly targets`.split("\n").grep(/^#{fly_target}/).first raise "invalid fly target #{fly_target}" unless matching_line matching_line.split(/ +/)[1] end
def add_pipeline(name, erb_filename)
def add_pipeline(name, erb_filename) @pipelines << Concourse::Pipeline.new(name, @directory, erb_filename) end
def create_tasks!
def create_tasks! unless Dir.exist? directory mkdir_p directory end pipelines.each do |pipeline| CLOBBER.include pipeline.filename if defined?(CLOBBER) unless File.exist? pipeline.erb_filename warn "WARNING: concourse template #{pipeline.erb_filename.inspect} does not exist, run `rake concourse:init`" end end namespace :concourse do # # project commands # desc "bootstrap a concourse config" task :init do rake_init end # # pipeline commands # desc "generate and validate all pipeline files" task "generate" => pipeline_subcommands("generate") pipelines.each do |pipeline| desc "generate and validate the #{pipeline.name} pipeline file" task "generate:#{pipeline.name}" do rake_pipeline_generate pipeline end end desc "upload all pipeline files" task "set" => pipeline_subcommands("set") pipelines.each do |pipeline| desc "upload the #{pipeline.name} pipeline file" task "set:#{pipeline.name}" => "generate:#{pipeline.name}" do options = [ "-p '#{pipeline.name}'", "-c '#{pipeline.filename}'", ] if File.exist? secrets_filename note "using #{secrets_filename} to resolve template vars in #{pipeline.filename}" options << "-l '#{secrets_filename}'" end fly "set-pipeline #{options.join(" ")}" end end %w[expose hide pause unpause destroy].each do |command| desc "#{command} all pipelines" task command => pipeline_subcommands(command) pipelines.each do |pipeline| desc "#{command} the #{pipeline.name} pipeline" task "#{command}:#{pipeline.name}" do fly "#{command}-pipeline -p #{pipeline.name}" end end end desc "remove generated pipeline files" task "clean" do pipelines.each do |pipeline| rm_f pipeline.filename end end # # task commands # desc "list all available tasks from all pipelines" task "tasks" => "generate" do tasks = [] pipelines.each do |pipeline| each_task(pipeline) do |job, task| tasks << "#{job["name"]}/#{task["task"]}" end end note "Available Concourse tasks for #{project_name} are:" tasks.sort.each { |task| puts " * #{task}" } end desc "fly execute the specified task" task "task", [:job_task, :fly_execute_args] => "generate" do |t, args| job_task = args[:job_task] unless job_task raise "ERROR: must specify a task name, like `rake #{t.name}[taskname]`" end concourse_task = find_task(job_task) raise "ERROR: could not find task `#{job_task}`" unless concourse_task fly_execute_args = args[:fly_execute_args] || Concourse.default_execute_args(concourse_task) if File.exist? secrets_filename note "using #{secrets_filename} to resolve template vars" fly_execute_args += " -l '#{secrets_filename}'" end puts concourse_task.to_yaml Tempfile.create("concourse-task") do |f| f.write concourse_task["config"].to_yaml f.close Bundler.with_clean_env do fly "execute #{fly_execute_args} -c #{f.path}" end end end # # builds commands # desc "abort all running builds for this concourse team" task "abort-builds" do |t, args| `fly -t #{fly_target} builds`.each_line do |line| pipeline_job, build_id, status = *line.split(/\s+/)[1, 3] next unless status == "started" fly "abort-build -j #{pipeline_job} -b #{build_id}" end end # # worker commands # desc "prune any stalled workers" task "prune-stalled-workers" do `fly -t #{fly_target} workers | fgrep stalled`.each_line do |line| worker_id = line.split.first fly "prune-worker -w #{worker_id}" end end # # docker commands # desc "set fly target to the local docker-compose cluster" task "local" do rake_concourse_local end namespace "local" do desc "start up a docker-compose cluster for local CI" task "up" do rake_concourse_local_up end desc "shut down the docker-compose cluster" task "down" do rake_concourse_local_down end end end end
def ensure_docker_compose_file
def ensure_docker_compose_file return if File.exist?(docker_compose_path) note "fetching docker compose file ..." File.open(docker_compose_path, "w") do |f| f.write open("https://concourse-ci.org/docker-compose.yml").read sh "docker pull concourse/concourse" end end
def initialize(project_name, options = {}, &block)
def initialize(project_name, options = {}, &block) @project_name = project_name @directory = options[:directory] || DEFAULT_DIRECTORY @fly_target = options[:fly_target] || DEFAULT_FLY_TARGET base_secrets_filename = options[:secrets_filename] || DEFAULT_SECRETS @secrets_filename = File.join(@directory, base_secrets_filename) @pipelines = [] if block block.call(self) create_tasks! else add_pipeline(@project_name, (options[:pipeline_erb_filename] || "#{project_name}.yml")) end end
def pipeline_subcommands(command)
def pipeline_subcommands(command) pipelines.collect { |p| "#{command}:#{p.name}" } end
def rake_concourse_local
def rake_concourse_local ensure_docker_compose_file @fly_target = "local" fly "login -u test -p test -c http://127.0.0.1:8080" end
def rake_concourse_local_down
def rake_concourse_local_down ensure_docker_compose_file docker_compose "down" end
def rake_concourse_local_up
def rake_concourse_local_up ensure_docker_compose_file docker_compose "up -d" docker_compose "ps" end
def rake_init
def rake_init FileUtils.mkdir_p File.join(directory, "tasks") pipelines.each do |pipeline| FileUtils.touch pipeline.erb_filename end ensure_in_gitignore secrets_filename end
def rake_pipeline_generate(pipeline)
def rake_pipeline_generate(pipeline) File.open pipeline.filename, "w" do |f| f.write erbify_file(pipeline.erb_filename, working_directory: directory) end fly "validate-pipeline -c #{pipeline.filename}" end