Skip to content

Instantly share code, notes, and snippets.

@sj26
Created July 19, 2018 04:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sj26/a251f1b3ec2454b07cc6ce8e79fca558 to your computer and use it in GitHub Desktop.
Save sj26/a251f1b3ec2454b07cc6ce8e79fca558 to your computer and use it in GitHub Desktop.
def link_to(url, content = nil)
if ENV["BUILDKITE"]
"\e]1339;url=#{url.gsub(";", "%3b")}#{";content=#{content.gsub(";", "%3b")}" if content}\a"
else
url
end
end
def system!(*args)
system(*args) or fail("Command exited with status #{$?.exitstatus}: #{args.join(" ")}")
end
def capture!(*args)
IO.popen(args, &:read).tap do
$?.success? or fail("Command exited with status #{$?.exitstatus}: #{args.join(" ")}")
end
end
def meta_data_get(name)
capture!("buildkite-agent", "meta-data", "get", name.to_s).chomp
end
def meta_data_set(name, value)
system!("buildkite-agent", "meta-data", "set", name.to_s, value.to_s)
end
require "buildkit"
token = ENV.fetch("BUILDKITE_TOKEN")
$buildkit = Buildkit.new(token: token)
templates = []
if ENV["PACKER"] && %w(0 n no f false).include?(ENV["PACKER"].strip.downcase)
puts "--- :fast_forward: You've asked me not to build anything"
elsif ENV["PACKER"] && %w(1 y yes t true).include?(ENV["PACKER"].strip.downcase)
puts "--- :allthethings: You've asked me to build everything"
templates = Dir["packer/*.json"].map { |path| File.basename(path, ".json") }
elsif ENV["PACKER"] && !ENV["PACKER"].strip.empty?
puts "--- :bow: You've asked me to build #{ENV["PACKER"]}"
templates = ENV["PACKER"].split(",").map(&:strip)
else
puts "+++ :thinking_face: Seeing if we need to build new images"
organization = ENV.fetch("BUILDKITE_ORGANIZATION_SLUG")
pipeline = ENV.fetch("BUILDKITE_PIPELINE_SLUG")
branch = ENV.fetch("BUILDKITE_BRANCH")
commit = ENV.fetch("BUILDKITE_COMMIT")
Dir["packer/*.json"].each do |path|
template = File.basename(path, ".json")
previous_build = nil
# If this is not the master branch then it's probably a pull request
# to look at the history of this branch for a packer build and diff
# from the previously built commit
if branch != "master"
previous_build = $buildkit.pipeline_builds(organization, pipeline, branch: branch, "meta_data[packer:build:#{template}]" => "true", page: 1, per_page: 1).first
end
# If this is master and we're running a pull request merge commit and
# the merged branch has a built packer image and nothing in packer
# has changed on master since this branch started then we can use the
# already-built image.
#
# Useful when the pull request image has already been tested and
# we're just merging to promote that image into production.
if !previous_build and
branch == "master" and
%r{Merge pull request #(?:\d+) from (?:[^/]+)/(?<previous_branch>.+)} =~ capture!("git", "show", commit, "--format=format:%s").chomp and
system("git", "diff", "--quiet", "#{capture!("git", "merge-base", "HEAD^1", "HEAD^2").chomp}...#{commit}^", "packer")
previous_build = $buildkit.pipeline_builds(organization, pipeline, branch: previous_branch, "meta_data[packer:build:#{template}]" => template, page: 1, per_page: 1).first
end
# Otherwise maybe there's a recent master build which we can use as a base for comparison
if !previous_build
previous_build = $buildkit.pipeline_builds(organization, pipeline, branch: "master", "meta_data[packer:build:#{template}]" => "true", page: 1, per_page: 1).first
end
# If we found a previous build then see if there have been any changes
if previous_build
# Make sure we have the commit we want to diff against
unless system "git", "cat-file", "-e", "#{previous_build.commit}^{commit}"
system! "git", "fetch", "origin", previous_build.commit
end
# Has this template been changed since then?
#
# XXX: This only considers the template file, not the scripts or
# any files for copying like services, etc. You must bump the
# template content to trigger an automatic packer build.
#
if not system("git", "diff", "--quiet", "--diff-filter", "ACMR", "#{previous_build.commit}...#{commit}", "--", "packer/#{template}.json")
puts "#{template} has been built on #{previous_build.branch} at #{previous_build.commit} in #{link_to(previous_build.web_url, "build #{previous_build.number}")} but packer template has changed, building."
templates << template
else
puts "#{template} has been built on #{previous_build.branch} at #{previous_build.commit} in #{link_to(previous_build.web_url, "build #{previous_build.number}")}."
end
else
puts "#{template} has never been built, building."
# We couldn't find a single build of this template! Definitely build it.
templates << template
end
end
end
templates.each do |template|
puts "+++ :thinking_face: Building #{template}"
system! "packer", "build", "packer/#{template}.json"
meta_data_set "packer:build:#{template}", "true"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment