Skip to content

Instantly share code, notes, and snippets.

@RulerOf
Last active July 2, 2025 23:34
Show Gist options
  • Save RulerOf/98d1e57bcb4436b7952e0b5e30ac479b to your computer and use it in GitHub Desktop.
Save RulerOf/98d1e57bcb4436b7952e0b5e30ac479b to your computer and use it in GitHub Desktop.
Dynamically generate a chef Berksfile from an existing Chef Policyfile.rb
require 'chef-cli/policyfile_services/install'
def policyfile_to_berksfile(policyfile_path)
pf = ChefCLI::PolicyfileServices::Install
.new(policyfile: policyfile_path)
.policyfile_compiler
# ------------------------------------------------------------------
# 1. Sources
# ------------------------------------------------------------------
sources = pf.default_source.map do |source|
case source
when ChefCLI::Policyfile::CommunityCookbookSource
%(source "#{source.uri}")
when ChefCLI::Policyfile::ChefServerCookbookSource
%(source :chef_server, "#{source.uri}")
end
end.compact
# ------------------------------------------------------------------
# 2. Cookbooks
# ------------------------------------------------------------------
current_cb = pf.dsl.name
cookbooks = pf.fixed_version_cookbooks_specs.map do |name, spec|
next if name == current_cb
case spec.source_type
when :path
%(cookbook '#{name}', path: '#{spec.source_options[:path]}')
when :git, :github
build_git_line(name, spec.source_type, spec.source_options)
else
nil
end
end.compact
# ------------------------------------------------------------------
# 3. Result
# ------------------------------------------------------------------
(sources + cookbooks + ['metadata']).join("\n")
end
# --------------------------------------------------------------------
# Helper: build a line for git / github sources
# --------------------------------------------------------------------
def build_git_line(name, type, opts)
# 1. Work out which form of the location we have
owner_repo =
opts[:github] ||
owner_repo_from_url(opts[:git])
if owner_repo # short form → github:
key = :github
val = owner_repo
else # everything else → git:
key = :git
val = opts[:git]
end
raise "Cannot determine repository for cookbook #{name}" if val.to_s.empty?
# 2. Put together the pin (ref / branch / tag)
parts = ["#{key}: '#{val}'"]
if (sha = opts[:revision] || opts[:ref])
parts << "ref: '#{sha}'"
elsif opts[:branch]
parts << "branch: '#{opts[:branch]}'"
elsif opts[:tag]
parts << "tag: '#{opts[:tag]}'"
end
"cookbook '#{name}', #{parts.join(', ')}"
end
# --------------------------------------------------------------------
# Pull "owner/repo" out of a GitHub URL if we need to
# --------------------------------------------------------------------
def owner_repo_from_url(url)
return unless url
# https://github.com/BuyerQuest/aws.git
# git://github.com/BuyerQuest/aws.git
# ssh://[email protected]/BuyerQuest/aws.git
if url =~ %r{\A(?:https?|git|ssh)://(?:[^@/]+@)?github\.com/([^/]+/[^/]+?)(?:\.git)?\z}i
return Regexp.last_match(1)
end
# [email protected]:BuyerQuest/aws.git
if url =~ %r{\Agit@github\.com:([^/]+/[^/]+?)(?:\.git)?\z}i
return Regexp.last_match(1)
end
end
# --------------------------------------------------------------------
# Kick things off
# --------------------------------------------------------------------
policyfile_path = File.expand_path('../Policyfile.rb', __FILE__)
eval(policyfile_to_berksfile(policyfile_path))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment