diff --git a/dev/lib/product_taxonomy.rb b/dev/lib/product_taxonomy.rb
index abb50a12..0a34fae6 100644
--- a/dev/lib/product_taxonomy.rb
+++ b/dev/lib/product_taxonomy.rb
@@ -34,3 +34,4 @@ def data_path = DATA_PATH
require_relative "product_taxonomy/commands/generate_dist_command"
require_relative "product_taxonomy/commands/find_unmapped_external_categories_command"
require_relative "product_taxonomy/commands/generate_docs_command"
+require_relative "product_taxonomy/commands/generate_release_command"
diff --git a/dev/lib/product_taxonomy/cli.rb b/dev/lib/product_taxonomy/cli.rb
index 221c0156..e112e3d4 100644
--- a/dev/lib/product_taxonomy/cli.rb
+++ b/dev/lib/product_taxonomy/cli.rb
@@ -32,5 +32,12 @@ def unmapped_external_categories(name_and_version)
def docs
GenerateDocsCommand.new(options).run
end
+
+ desc "release", "Generate a release"
+ option :version, type: :string, desc: "The version of the release to generate"
+ option :locales, type: :array, default: ["en"], desc: "The locales to generate"
+ def release
+ GenerateReleaseCommand.new(options).run
+ end
end
end
diff --git a/dev/lib/product_taxonomy/commands/command.rb b/dev/lib/product_taxonomy/commands/command.rb
index 74139b3c..bc31ebc0 100644
--- a/dev/lib/product_taxonomy/commands/command.rb
+++ b/dev/lib/product_taxonomy/commands/command.rb
@@ -20,6 +20,9 @@ def run(...)
execute(...)
end
logger.info("Completed in #{elapsed.round(2)} seconds")
+ rescue => e
+ logger.error("\e[1;31mError:\e[0m #{e.message}")
+ exit(1)
end
def execute(...)
@@ -27,6 +30,8 @@ def execute(...)
end
def load_taxonomy
+ return if ProductTaxonomy::Category.all.any?
+
ProductTaxonomy::Value.load_from_source(YAML.load_file(File.expand_path(
"values.yml",
ProductTaxonomy.data_path,
@@ -54,5 +59,14 @@ def validate_and_sanitize_version!(version)
sanitized_version
end
+
+ def version_file_path
+ File.expand_path("../VERSION", ProductTaxonomy.data_path)
+ end
+
+ def locales_defined_in_data_path
+ glob = Dir.glob(File.expand_path("localizations/categories/*.yml", ProductTaxonomy.data_path))
+ glob.map { File.basename(_1, ".yml") }
+ end
end
end
diff --git a/dev/lib/product_taxonomy/commands/generate_dist_command.rb b/dev/lib/product_taxonomy/commands/generate_dist_command.rb
index 69fd5ae3..f861d5b4 100644
--- a/dev/lib/product_taxonomy/commands/generate_dist_command.rb
+++ b/dev/lib/product_taxonomy/commands/generate_dist_command.rb
@@ -7,7 +7,7 @@ class GenerateDistCommand < Command
def initialize(options)
super
- @version = options[:version] || File.read(File.expand_path("../../../../VERSION", __dir__)).strip
+ @version = options[:version] || File.read(version_file_path).strip
@locales = if options[:locales] == ["all"]
glob = Dir.glob(File.expand_path("localizations/categories/*.yml", ProductTaxonomy.data_path))
glob.map { File.basename(_1, ".yml") }
diff --git a/dev/lib/product_taxonomy/commands/generate_release_command.rb b/dev/lib/product_taxonomy/commands/generate_release_command.rb
new file mode 100644
index 00000000..7f9c4d45
--- /dev/null
+++ b/dev/lib/product_taxonomy/commands/generate_release_command.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module ProductTaxonomy
+ class GenerateReleaseCommand < Command
+ def initialize(options)
+ super
+
+ @version = options[:version] || File.read(version_file_path).strip
+ @locales = if options[:locales] == ["all"]
+ locales_defined_in_data_path
+ else
+ options[:locales]
+ end
+ end
+
+ def execute
+ logger.info("Generating release for version: #{@version}")
+
+ logger.info("Generating distribution files...")
+ GenerateDistCommand.new(version: @version, locales: @locales).execute
+
+ logger.info("Generating documentation files...")
+ GenerateDocsCommand.new(version: @version, locales: @locales).execute
+
+ logger.info("Updating VERSION file...")
+ File.write(version_file_path, @version)
+
+ logger.info("Creating git tag...")
+ system("git", "tag", "v#{@version}")
+
+ logger.info("Updating README.md...")
+ update_readme
+ end
+
+ private
+
+ def update_readme
+ readme_path = File.expand_path("../dist/README.md", ProductTaxonomy.data_path)
+ content = File.read(readme_path)
+ content.gsub!(%r{badge/Version-.*?-blue\.svg}) do
+ badge_version = @version.gsub("-", "--")
+ "badge/Version-#{badge_version}-blue.svg"
+ end
+ File.write(readme_path, content)
+ end
+ end
+end
diff --git a/dev/test/commands/generate_release_command_test.rb b/dev/test/commands/generate_release_command_test.rb
new file mode 100644
index 00000000..8b672d5b
--- /dev/null
+++ b/dev/test/commands/generate_release_command_test.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require "test_helper"
+require "tmpdir"
+
+module ProductTaxonomy
+ class GenerateReleaseCommandTest < TestCase
+ setup do
+ @tmp_base_path = Dir.mktmpdir
+ @version = "2024-01"
+ @version_file_path = File.expand_path("VERSION", @tmp_base_path)
+
+ # Create test files and directories
+ FileUtils.mkdir_p(File.expand_path("dist", @tmp_base_path))
+ File.write(@version_file_path, "2023-12")
+ File.write(
+ File.expand_path("dist/README.md", @tmp_base_path),
+ '
',
+ )
+
+ # Stub dependencies
+ Command.any_instance.stubs(:version_file_path).returns(@version_file_path)
+ Command.any_instance.stubs(:load_taxonomy)
+ GenerateDistCommand.any_instance.stubs(:execute)
+ GenerateDocsCommand.any_instance.stubs(:execute)
+ ProductTaxonomy.stubs(:data_path).returns("#{@tmp_base_path}/data")
+ end
+
+ teardown do
+ FileUtils.remove_entry(@tmp_base_path)
+ end
+
+ test "initialize sets version from options if provided" do
+ command = GenerateReleaseCommand.new(version: @version)
+ assert_equal @version, command.instance_variable_get(:@version)
+ end
+
+ test "initialize reads version from file if not provided in options" do
+ command = GenerateReleaseCommand.new({})
+ assert_equal "2023-12", command.instance_variable_get(:@version)
+ end
+
+ test "initialize sets all locales when 'all' is specified" do
+ Command.any_instance.stubs(:locales_defined_in_data_path).returns(["en", "fr", "es"])
+ command = GenerateReleaseCommand.new(locales: ["all"])
+ assert_equal ["en", "fr", "es"], command.instance_variable_get(:@locales)
+ end
+
+ test "initialize sets specific locales when provided" do
+ command = GenerateReleaseCommand.new(locales: ["en", "fr"])
+ assert_equal ["en", "fr"], command.instance_variable_get(:@locales)
+ end
+
+ test "execute performs all required steps in order" do
+ command = GenerateReleaseCommand.new(version: @version, locales: ["en"])
+
+ # Set up expectations
+ GenerateDistCommand.any_instance.expects(:execute)
+ GenerateDocsCommand.any_instance.expects(:execute)
+ command.expects(:system).with("git", "tag", "v#{@version}")
+
+ command.execute
+
+ # Verify VERSION file was updated
+ assert_equal @version, File.read(@version_file_path)
+ end
+
+ test "execute updates README.md version badge" do
+ command = GenerateReleaseCommand.new(version: @version)
+
+ command.execute
+
+ readme_content = File.read(File.expand_path("dist/README.md", @tmp_base_path))
+ assert_equal '
', readme_content
+ end
+ end
+end