Skip to content

Commit 76caea8

Browse files
authored
Merge pull request #168 from OpenVoxProject/fix_rake_tasks
Refactor Vox rake tasks
2 parents 2362f50 + a047f2b commit 76caea8

File tree

10 files changed

+361
-297
lines changed

10 files changed

+361
-297
lines changed

Rakefile

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,4 @@
11
require 'rake'
2-
require 'open3'
3-
4-
RED = "\033[31m"
5-
GREEN = "\033[32m"
6-
RESET = "\033[0m"
7-
8-
def run_command(cmd, silent: true, print_command: false, report_status: false, allowed_exit_codes: [0])
9-
puts "#{GREEN}Running #{cmd}#{RESET}" if print_command
10-
output = ''
11-
Open3.popen2e(cmd) do |_stdin, stdout_stderr, thread|
12-
stdout_stderr.each do |line|
13-
puts line unless silent
14-
output += line
15-
end
16-
exitcode = thread.value.exitstatus
17-
unless allowed_exit_codes.include?(exitcode)
18-
err = "#{RED}Command failed! Command: #{cmd}, Exit code: #{exitcode}"
19-
# Print details if we were running silent
20-
err += "\nOutput:\n#{output}" if silent
21-
err += RESET
22-
abort err
23-
end
24-
puts "#{GREEN}Command finished with status #{exitcode}#{RESET}" if report_status
25-
end
26-
output.chomp
27-
end
28-
29-
Dir.glob(File.join('tasks/**/*.rake')).each { |file| load file }
302

313
### puppetlabs stuff ###
324
def run_beaker(test_files)
@@ -211,30 +183,3 @@ namespace :release do
211183
end
212184
end
213185
end
214-
215-
begin
216-
require 'github_changelog_generator/task'
217-
rescue LoadError
218-
task :changelog do
219-
abort('Run `bundle install --with release` to install the `github_changelog_generator` gem.')
220-
end
221-
else
222-
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
223-
config.header = <<~HEADER.chomp
224-
# Changelog
225-
226-
All notable changes to this project will be documented in this file.
227-
HEADER
228-
config.user = 'openvoxproject'
229-
config.project = 'openvoxdb'
230-
config.exclude_labels = %w[dependencies duplicate question invalid wontfix wont-fix modulesync skip-changelog]
231-
# this is probably the worst way to do this
232-
# ideally there would be a VERSION file and clojure and Rake would read it
233-
config.future_release = File.readlines('project.clj').first.scan(/".*"/).first.gsub('"', '')
234-
# we limit the changelog to all new openvox releases, to skip perforce onces
235-
# otherwise the changelog generate takes a lot amount of time
236-
config.since_tag = '8.9.1'
237-
#config.exclude_tags_regex = /\A7\./
238-
config.release_branch = 'main'
239-
end
240-
end

rakelib/build.rake

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# frozen_string_literal: true
2+
3+
# Builds packages using a Docker container
4+
# Env var options:
5+
# NO_TEARDOWN - If set, do not stop the docker container after the build for debugging purposes.
6+
# EZBAKE_BRANCH - If set, use this ezbake branch for building. If used, must also set EZBAKE_VERSION accordingly.
7+
# EZBAKE_REPO - If EZBAKE_BRANCH is set, use this repo URL for ezbake (default: https://github.com/openvoxproject/ezbake)
8+
# EZBAKE_VERSION - If set, use this version string in project.clj for ezbake. Must correspond to the version currently in defproject
9+
# in EZBAKE_BRANCH.
10+
# FULL_DEP_REBUILD_BRANCH - If set, rebuild all dependencies, where all dependency repos have this branch present with your
11+
# desired changes. Overrides any other DEP_ settings.
12+
# DEP_REBUILD - Comma-separated list of dependencies to rebuild from source. Should be the repo names.
13+
# DEP_REBUILD_BRANCH - If DEP_REBUILD is set, use this branch for the specified dependencies (default: main)
14+
# DEP_REBUILD_ORG - If DEP_REBUILD is set, use this GitHub org for the specified dependencies to build the repo URL (default: openvoxproject)
15+
# DEB_PLATFORMS - Comma-separated list of debian/ubuntu platforms to build for
16+
# RPM_PLATFORMS - Comma-separated list of rpm platforms to build for
17+
# FIPS - If set, build specified platforms with the appropriate 'fips' lein profile(s) enabled.
18+
19+
require 'fileutils'
20+
require 'tmpdir'
21+
require_relative 'utils/docker_runner'
22+
23+
module Vox
24+
class Build
25+
def platform_targets
26+
# It seems like these are special files/names that, when you want to add a new one, require
27+
# changes in some other component. But no, it seems to only really look at the parts of
28+
# the text in the string, as long as it looks like "base-<whatever you want to call the platform>-i386.cow"
29+
# and "<doesn't matter>-<os>-<osver>-<arch which doesn't matter because it's actually noarch>".
30+
# I think it just treats all debs like Debian these days. And all rpms are similar.
31+
# So do whatever you want I guess. We really don't need separate packages for each platform.
32+
# To be fixed one of these days. Relevant stuff:
33+
# https://github.com/puppetlabs/ezbake/blob/aeb7735a16d2eecd389a6bd9e5c0cfc7c62e61a5/resources/puppetlabs/lein-ezbake/template/global/tasks/build.rake
34+
# https://github.com/puppetlabs/ezbake/blob/aeb7735a16d2eecd389a6bd9e5c0cfc7c62e61a5/resources/puppetlabs/lein-ezbake/template/global/ext/fpm.rb
35+
deb_platforms = ENV['DEB_PLATFORMS'] || 'ubuntu-20.04,ubuntu-22.04,ubuntu-24.04,ubuntu-25.04,debian-11,debian-12,debian-13'
36+
rpm_platforms = ENV['RPM_PLATFORMS'] || 'el-8,el-9,el-10,sles-15,sles-16,amazon-2,amazon-2023,fedora-42,fedora-43'
37+
38+
debs = deb_platforms.split(',').map { |p| "base-#{p.split("-").join}-i386.cow" }.join(" ")
39+
rpms = rpm_platforms.split(',').map { |p| "pl-#{p}-x86_64" }.join(" ")
40+
41+
[debs, rpms]
42+
end
43+
# The deps must be built in this order due to dependencies between them.
44+
# There is a circular dependency between clj-http-client and trapperkeeper-webserver-jetty10,
45+
# but only for tests, so the build *should* work.
46+
DEP_BUILD_ORDER = [
47+
'clj-parent',
48+
'clj-kitchensink',
49+
'clj-i18n',
50+
'comidi',
51+
'jvm-ssl-utils',
52+
'trapperkeeper',
53+
'trapperkeeper-filesystem-watcher',
54+
'trapperkeeper-webserver-jetty10',
55+
'trapperkeeper-authorization',
56+
'trapperkeeper-metrics',
57+
'trapperkeeper-status',
58+
'stockpile',
59+
'structured-logging',
60+
].freeze
61+
62+
def initialize(tag:)
63+
@tag = tag
64+
@runner = Vox::DockerRunner.new(container_name: 'openvoxdb-builder', image: 'ezbake-builder')
65+
@deps_tmp = Dir.mktmpdir('deps')
66+
end
67+
68+
def build
69+
checkout_tag_if_requested
70+
build_image_unless_present
71+
start_container
72+
build_and_install_libs(prepare_deps)
73+
build_project
74+
postprocess_output
75+
ensure
76+
@runner.teardown unless ENV['NO_TEARDOWN']
77+
FileUtils.rm_rf(@deps_tmp)
78+
end
79+
80+
private
81+
82+
def checkout_tag_if_requested
83+
if @tag.nil? || @tag.empty?
84+
puts 'Running build with current branch'
85+
else
86+
puts "Running build on #{@tag}"
87+
Vox::Shell.run("git fetch --tags && git checkout #{@tag}")
88+
end
89+
end
90+
91+
def build_image_unless_present
92+
return if @runner.image_exists?
93+
94+
# If the Dockerfile has changed since this was last built,
95+
# delete all containers and do `docker rmi ezbake-builder`
96+
puts 'Building ezbake-builder image'
97+
Vox::Shell.run("docker build -t ezbake-builder .", silent: false, print_command: true)
98+
end
99+
100+
def prepare_deps
101+
libs = {}
102+
103+
# Manage ezbake override
104+
ezbake_branch = ENV.fetch('EZBAKE_BRANCH', '').strip
105+
unless ezbake_branch.empty?
106+
libs['ezbake'] = {
107+
repo: ENV.fetch('EZBAKE_REPO', 'https://github.com/openvoxproject/ezbake'),
108+
branch: ENV.fetch('EZBAKE_BRANCH', 'main'),
109+
}
110+
end
111+
112+
# Decide if we're rebuilding everything or a subset
113+
full_rebuild_branch = ENV.fetch('FULL_DEP_REBUILD_BRANCH', '').strip
114+
subset_list = ENV.fetch('DEP_REBUILD', '').split(',').map(&:strip).reject(&:empty?)
115+
subset_branch = ENV.fetch('DEP_REBUILD_BRANCH', 'main').strip
116+
rebuild_org = ENV.fetch('DEP_REBUILD_ORG', 'openvoxproject').strip
117+
118+
selected_libs = []
119+
selected_branch = nil
120+
121+
if !full_rebuild_branch.empty?
122+
selected_branch = full_rebuild_branch
123+
selected_libs = DEP_BUILD_ORDER.dup
124+
elsif !subset_list.empty?
125+
selected_branch = subset_branch
126+
unknown = subset_list - DEP_BUILD_ORDER
127+
puts "WARNING: Unknown deps in DEP_REBUILD (will be ignored): #{unknown.join(', ')}" unless unknown.empty?
128+
selected_libs = DEP_BUILD_ORDER & subset_list # Keeps DEP_BUILD_ORDER ordering
129+
end
130+
131+
selected_libs.each do |lib|
132+
libs[lib] = { repo: "https://github.com/#{rebuild_org}/#{lib}", branch: selected_branch }
133+
end
134+
135+
libs.each do |lib, config|
136+
puts "Checking out #{lib}"
137+
Vox::Shell.run(
138+
"git clone --revision #{config[:branch]} #{config[:repo]} #{@deps_tmp}/#{lib}",
139+
silent: false,
140+
print_command: true
141+
)
142+
end
143+
144+
libs
145+
end
146+
147+
def start_container
148+
@runner.teardown if @runner.container_exists?
149+
volumes = [[Dir.pwd, '/code'], [@deps_tmp, '/deps']]
150+
@runner.start(volumes: volumes)
151+
end
152+
153+
def build_and_install_libs(libs)
154+
libs.each_key do |lib|
155+
puts "Building and installing #{lib} from source"
156+
@runner.exec("cd /deps/#{lib} && lein install")
157+
end
158+
end
159+
160+
def build_project
161+
debs, rpms = platform_targets
162+
fips = !ENV['FIPS'].nil?
163+
ezbake_version_var = ENV['EZBAKE_VERSION'] ? "EZBAKE_VERSION=#{ENV['EZBAKE_VERSION']}" : ""
164+
165+
puts 'Building openvoxdb'
166+
@runner.exec('cd /code && rm -rf ruby output && bundle install --without test && lein install')
167+
@runner.exec(
168+
"cd /code && COW=\"#{debs}\" MOCK=\"#{rpms}\" GEM_SOURCE='https://rubygems.org' #{ezbake_version_var} " \
169+
"EZBAKE_ALLOW_UNREPRODUCIBLE_BUILDS=true EZBAKE_NODEPLOY=true LEIN_PROFILES=ezbake " \
170+
"lein with-profile #{fips ? "fips," : ""}user,ezbake,provided,internal ezbake local-build"
171+
)
172+
end
173+
174+
def postprocess_output
175+
Vox::Shell.run("sudo chown -R $USER output", print_command: true)
176+
Dir.glob("output/**/*i386*").each { |f| FileUtils.rm_rf(f) }
177+
Dir.glob("output/puppetdb-*.tar.gz").each { |f| FileUtils.mv(f, f.sub('puppetdb', 'openvoxdb')) }
178+
end
179+
end
180+
end
181+
182+
namespace :vox do
183+
desc 'Build openvoxdb packages with Docker'
184+
task :build, [:tag] do |_, args|
185+
Vox::Build.new(tag: args[:tag]).build
186+
end
187+
end

rakelib/changelog.rake

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# frozen_string_literal: true
2+
3+
begin
4+
require 'github_changelog_generator/task'
5+
rescue LoadError
6+
task :changelog do
7+
abort('Run `bundle install --with release` to install the `github_changelog_generator` gem.')
8+
end
9+
else
10+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
11+
config.header = <<~HEADER.chomp
12+
# Changelog
13+
14+
All notable changes to this project will be documented in this file.
15+
HEADER
16+
config.user = 'openvoxproject'
17+
config.project = 'openvoxdb'
18+
config.exclude_labels = %w[dependencies duplicate question invalid wontfix wont-fix modulesync skip-changelog]
19+
# this is probably the worst way to do this
20+
# ideally there would be a VERSION file and clojure and Rake would read it
21+
config.future_release = File.readlines('project.clj').first.scan(/".*"/).first.gsub('"', '')
22+
# we limit the changelog to all new openvox releases, to skip perforce onces
23+
# otherwise the changelog generate takes a lot amount of time
24+
config.since_tag = '8.9.1'
25+
#config.exclude_tags_regex = /\A7\./
26+
config.release_branch = 'main'
27+
end
28+
end

rakelib/test.rake

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# frozen_string_literal: true
2+
3+
# Tests OpenVoxDB in the same manner as we do in PR tests.
4+
# Only tested with a handful of the cells we use in CI. May need adjustment for others.
5+
#
6+
# Env var options:
7+
# NO_TEARDOWN - If set, do not stop the docker container after the tests for debugging purposes.
8+
9+
require_relative 'utils/docker_runner'
10+
11+
module Vox
12+
class Test
13+
def initialize(spec:)
14+
@spec = spec
15+
@runner = Vox::DockerRunner.new(container_name: 'openvoxdb-test', image: select_image(@spec))
16+
end
17+
18+
def run_tests
19+
@runner.teardown if @runner.container_exists?
20+
@runner.start(volumes: [[Dir.pwd, '/code']])
21+
22+
# The tests make tons of temp dirs in the current working directory, and trying to do this
23+
# inside the volume mount dir results in permissions issues. So we copy all of the code to /tmp/code
24+
# and run from there. Not ideal, but we have to since it curls down pdbbox and we don't control that.
25+
@runner.exec('cp -r /code /tmp && chown -R root:root /tmp/code')
26+
@runner.exec('apt update && apt install -y leiningen curl python3 procps')
27+
@runner.exec("cd /tmp/code && rm -rf ci/local && ext/bin/prep-debianish-root --for #{@spec} --install ci/local")
28+
@runner.exec('echo "postgres ALL=(ALL:ALL) NOPASSWD:ALL" >> /etc/sudoers')
29+
# There is a non-fatal error when running on an arm64 host, so we can ignore exit 255.
30+
@runner.exec("cd /tmp/code && ci/bin/prep-and-run-in local #{@spec}", allowed_exit_codes: [0, 255])
31+
@runner.exec('chown -R postgres:postgres /tmp/code')
32+
@runner.exec("cd /tmp/code && NO_ACCEPTANCE=true ci/bin/run #{@spec}", user: 'postgres')
33+
ensure
34+
@runner.teardown unless ENV['NO_TEARDOWN']
35+
end
36+
37+
private
38+
39+
def select_image(spec)
40+
_suite, java, _pg = spec.split('/')
41+
java =~ /17/ ? 'ruby:3.2-bookworm' : 'ruby:3.2-trixie'
42+
end
43+
end
44+
end
45+
46+
namespace :vox do
47+
desc 'Run lein test locally in the same way that PR checks run with a properly configured postgres and other artifacts.'
48+
task :test, [:spec] do |_, args|
49+
Vox::Test.new(spec: (args[:spec] || 'core+ext/openjdk17/pg-17')).run_tests
50+
end
51+
end
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
require_relative 'utils/shell'
4+
15
namespace :vox do
26
desc 'Upload artifacts from the output directory to S3. Requires the AWS CLI to be installed and configured appropriately.'
37
task :upload, [:platform] do |_, args|
48
endpoint = ENV.fetch('ENDPOINT_URL')
59
bucket = ENV.fetch('BUCKET_NAME')
610
component = 'openvoxdb'
711
os = nil
8-
arch = nil
912
if args[:platform]
1013
parts = args[:platform].split('-')
1114
os = parts[0].gsub('fedora','fc') + parts[1]
12-
arch = parts[2]
1315
end
1416

1517
abort 'You must set the ENDPOINT_URL environment variable to the S3 server you want to upload to.' if endpoint.nil? || endpoint.empty?
@@ -18,7 +20,7 @@ namespace :vox do
1820
s3 = "aws s3 --endpoint-url=#{endpoint}"
1921

2022
# Ensure the AWS CLI isn't going to fail with the given parameters
21-
run_command("#{s3} ls s3://#{bucket}/")
23+
Vox::Shell.run("#{s3} ls s3://#{bucket}/")
2224

2325
config = File.expand_path("../target/staging/ezbake.rb", __dir__)
2426
abort "Could not find ezbake config from the build at #{config}" unless File.exist?(config)
@@ -40,7 +42,7 @@ namespace :vox do
4042

4143
path = "s3://#{bucket}/#{component}/#{tag}"
4244
files.each do |f|
43-
run_command("#{s3} cp #{f} #{path}/#{File.basename(f)}", silent: false)
45+
Vox::Shell.run("#{s3} cp #{f} #{path}/#{File.basename(f)}", silent: false)
4446
end
4547
end
4648
end

0 commit comments

Comments
 (0)