class Helper
	
	
	Helper class for performing gem-related operations like building, installing, and publishing gems.
Definitions
def initialize(root = Dir.pwd, gemspec: nil)
Initialize a new helper with the specified root directory and optional gemspec.
Signature
	- 
					parameter 
rootString The root directory of the gem project.
- 
					parameter 
gemspecGem::Specification | Nil The gemspec to use, or nil to find it automatically.
Implementation
						def initialize(root = Dir.pwd, gemspec: nil)
	@root = root
	@gemspec = gemspec || find_gemspec
end
					attr :root
Signature
	- 
					attribute 
String The root directory of the gem project.
attr :gemspec
Signature
	- 
					attribute 
Gem::Specification The gemspec for the gem.
def version_path
Find the path to the version.rb file in the gem.
Signature
	- 
					returns 
String | Nil The path to the version file, or nil if not found.
Implementation
						def version_path
	if @gemspec
		@gemspec.files.grep(/lib(.*?)\/version.rb/).first
	end
end
					def update_version(bump, version_path = self.version_path)
Update the version number in the version file according to the bump specification.
Signature
	- 
					parameter 
bumpArray(Integer) Array specifying how to increment each version part.
- 
					parameter 
version_pathString The path to the version file.
- 
					returns 
String | Boolean The path to the version file if updated, or false if no version file found.
Implementation
						def update_version(bump, version_path = self.version_path)
	return false unless version_path
	
	# Guard against consecutive version bumps
	guard_last_commit_not_version_bump
	
	lines = File.readlines(version_path)
	new_version = nil
	
	lines.each do |line|
		Version.update_version(line) do |version|
			new_version = version.increment(bump)
		end
	end
	
	if new_version
		File.write(version_path, lines.join)
		
		if block_given?
			yield new_version
		end
		
		return version_path
	end
end
					def guard_clean
Verify that the repository has no uncommitted changes.
Signature
	- 
					returns 
Boolean True if the repository is clean.
- 
					raises 
RuntimeError If there are uncommitted changes in the repository.
Implementation
						def guard_clean
	lines = readlines("git", "status", "--porcelain", chdir: @root)
	
	if lines.any?
		raise "Repository has uncommited changes!\n#{lines.join('')}"
	end
	
	return true
end
					def guard_last_commit_not_version_bump
Verify that the last commit was not a version bump.
Signature
	- 
					returns 
Boolean True if the last commit was not a version bump.
- 
					raises 
RuntimeError If the last commit was a version bump.
Implementation
						def guard_last_commit_not_version_bump
	# Get the last commit message:
	begin
		last_commit_message = readlines("git", "log", "-1", "--pretty=format:%s", chdir: @root).first&.strip
	rescue CommandExecutionError => error
		# If git log fails (e.g., no commits yet), skip the check:
		if error.exit_code == 128
			return true
		else
			raise
		end
	end
	
	if last_commit_message && last_commit_message.match?(/^Bump (patch|minor|major|version)( version)?\.?$/i)
		raise "Last commit appears to be a version bump: #{last_commit_message.inspect}. Cannot bump version consecutively."
	end
	
	return true
end
					def build_gem(root: "pkg", signing_key: nil)
Signature
	- 
					parameter 
rootString The root path for package files.
- 
					parameter 
signing_keyString | Nil The signing key to use for signing the package.
- 
					returns 
String The path to the built gem package.
Implementation
						def build_gem(root: "pkg", signing_key: nil)
	# Ensure the output directory exists:
	FileUtils.mkdir_p(root)
	
	output_path = File.join(root, @gemspec.file_name)
	
	if signing_key == false
		@gemspec.signing_key = nil
	elsif signing_key.is_a?(String)
		@gemspec.signing_key = signing_key
	elsif signing_key == true and @gemspec.signing_key.nil?
		raise ArgumentError, "Signing key is required for signing the gem, but none was specified by the gemspec."
	end
	
	::Gem::Package.build(@gemspec, false, false, output_path)
end
					def install_gem(*arguments, path: @gemspec.file_name)
Install the gem using the gem install command.
Signature
	- 
					parameter 
argumentsArray Additional arguments to pass to
gem install.- 
					parameter 
pathString The path to the gem file to install.
Implementation
						def install_gem(*arguments, path: @gemspec.file_name)
	system("gem", "install", path, *arguments)
end
					def push_gem(*arguments, path: @gemspec.file_name)
Push the gem to a gem repository using the gem push command.
Signature
	- 
					parameter 
argumentsArray Additional arguments to pass to
gem push.- 
					parameter 
pathString The path to the gem file to push.
Implementation
						def push_gem(*arguments, path: @gemspec.file_name)
	system("gem", "push", path, *arguments)
end
					def build_gem_in_worktree(root: "pkg", signing_key: nil)
Build the gem in a clean worktree for better isolation
Signature
	- 
					parameter 
rootString The root path for package files.
- 
					parameter 
signing_keyString | Nil The signing key to use for signing the package.
- 
					returns 
String The path to the built gem package.
Implementation
						def build_gem_in_worktree(root: "pkg", signing_key: nil)
	original_pkg_path = File.join(@root, root)
	
	# Create a unique temporary path for the worktree
	timestamp = Time.now.strftime("%Y%m%d-%H%M%S-%N")
	worktree_path = File.join(Dir.tmpdir, "bake-gem-build-#{timestamp}")
	
	begin
		# Create worktree from current HEAD
		unless system("git", "worktree", "add", worktree_path, "HEAD", chdir: @root)
			raise "Failed to create git worktree. Make sure you have at least one commit in the repository."
		end
		
		# Create helper for the worktree
		worktree_helper = self.class.new(worktree_path)
		
		# Build gem directly into the target pkg directory
		output_path = worktree_helper.build_gem(root: original_pkg_path, signing_key: signing_key)
		
		output_path
	ensure
		# Clean up the worktree
		system("git", "worktree", "remove", worktree_path, "--force", chdir: @root)
	end
end
					def create_release_branch(version_path, message: "Bump version.")
Create a release branch, add the version file, and commit the changes.
Signature
	- 
					parameter 
version_pathString The path to the version file that was updated.
- 
					parameter 
messageString The commit message to use.
- 
					returns 
String The name of the created branch.
Implementation
						def create_release_branch(version_path, message: "Bump version.")
	branch_name = "release-v#{@gemspec.version}"
	
	system("git", "checkout", "-b", branch_name, chdir: @root)
	system("git", "add", version_path, chdir: @root)
	system("git", "commit", "-m", message, chdir: @root)
	
	return branch_name
end
					def commit_version_changes(message: "Bump version.")
Commit version changes to the current branch.
Signature
	- 
					parameter 
messageString The commit message to use.
Implementation
						def commit_version_changes(message: "Bump version.")
	system("git", "add", "--all", chdir: @root)
	system("git", "commit", "-m", message, chdir: @root)
end
					def create_release_tag(tag: true, version:)
Fetch remote tags and create a release tag for the specified version.
Signature
	- 
					parameter 
tagBoolean Whether to tag the release.
- 
					parameter 
versionString The version to tag.
- 
					returns 
String | Nil The tag name if created, nil otherwise.
Implementation
						def create_release_tag(tag: true, version:)
	tag_name = nil
	
	if tag
		tag_name = "v#{version}"
		system("git", "fetch", "--all", "--tags", chdir: @root)
		system("git", "tag", tag_name, chdir: @root)
	end
	
	return tag_name
end
					def delete_git_tag(tag_name)
Delete a git tag.
Signature
	- 
					parameter 
tag_nameString The name of the tag to delete.
Implementation
						def delete_git_tag(tag_name)
	system("git", "tag", "--delete", tag_name, chdir: @root)
end
					def push_release(current_branch: nil)
Push changes and tags to the remote repository.
Signature
	- 
					parameter 
current_branchString | Nil The current branch name, or nil if not on a branch.
Implementation
						def push_release(current_branch: nil)
	# If we are on a branch, push, otherwise just push the tags (assuming shallow checkout):
	if current_branch
		system("git", "push", chdir: @root)
	end
	
	system("git", "push", "--tags", chdir: @root)
end
					def current_branch
Figure out if there is a current branch, if not, return nil.
Signature
	- 
					returns 
String | Nil The current branch name, or nil if not on a branch.
Implementation
						def current_branch
	# We originally used this but it is not supported by older versions of git.
	# readlines("git", "branch", "--show-current").first&.chomp
	
	readlines("git", "symbolic-ref", "--short", "--quiet", "HEAD", chdir: @root).first&.chomp
rescue CommandExecutionError
	nil
end
					def find_gemspec(glob = "*.gemspec")
Find a gemspec file in the root directory.
Signature
	- 
					parameter 
globString The glob pattern to use for finding gemspec files.
- 
					returns 
Gem::Specification | Nil The loaded gemspec, or nil if none found.
- 
					raises 
RuntimeError If multiple gemspec files are found.
Implementation
						def find_gemspec(glob = "*.gemspec")
	paths = Dir.glob(glob, base: @root).sort
	
	if paths.size > 1
		raise "Multiple gemspecs found: #{paths}, please specify one!"
	end
	
	if path = paths.first
		return ::Gem::Specification.load(File.expand_path(path, @root))
	end
end