diff --git a/lib/committer/commit_generator.rb b/lib/committer/commit_generator.rb index d0878b3..0e8d4a6 100644 --- a/lib/committer/commit_generator.rb +++ b/lib/committer/commit_generator.rb @@ -16,9 +16,8 @@ def initialize(diff, commit_context = nil) end def build_commit_prompt - format(template, - diff: @diff, - commit_context: @commit_context) + scopes = Committer::Config::Accessor.instance[:scopes] || [] + Committer::PromptTemplates.build_prompt(diff, scopes, commit_context) end def template diff --git a/lib/committer/config/accessor.rb b/lib/committer/config/accessor.rb index b1120c7..3e6ee8a 100644 --- a/lib/committer/config/accessor.rb +++ b/lib/committer/config/accessor.rb @@ -52,10 +52,6 @@ def read_file_from_path(path) File.read(path) end - def load_formatting_rules - read_path_prioritized_file(Committer::Config::Constants::FORMATTING_RULES_FILE_NAME) - end - def read_file_from_git_root(file_name) read_file_from_path(File.join(Committer::GitHelper.repo_root, '.committer', file_name)) end diff --git a/lib/committer/config/constants.rb b/lib/committer/config/constants.rb index ca638f9..53dbbbd 100644 --- a/lib/committer/config/constants.rb +++ b/lib/committer/config/constants.rb @@ -6,7 +6,8 @@ module Constants CONFIG_DIR = File.join(Dir.home, '.committer') DEFAULTS_PATH = File.join(File.dirname(__FILE__), './defaults') - FORMATTING_RULES_FILE_NAME = 'formatting_rules.txt' + COMMIT_MESSAGE_ONLY_PROMPT_FILE_NAME = 'commit_message_only.prompt' + COMMIT_MESSAGE_AND_BODY_PROMPT_FILE_NAME = 'commit_message_and_body.prompt' CONFIG_FILE_NAME = 'config.yml' DEFAULT_CONFIG = { diff --git a/lib/committer/config/defaults/commit_message_and_body.prompt b/lib/committer/config/defaults/commit_message_and_body.prompt new file mode 100644 index 0000000..c27b52e --- /dev/null +++ b/lib/committer/config/defaults/commit_message_and_body.prompt @@ -0,0 +1,52 @@ +You are an experienced software developer tasked with creating a commit message based on a git diff. Your goal is to produce a clear, concise, and informative commit message. + +First, carefully analyze the following git diff: + + +{{DIFF}} + + +Here are the available scopes (if any): + + +{{SCOPES}} + + + +{{CONTEXT}} + + +Please follow these instructions to generate the commit message: + +1. Analyze the git diff and determine the most appropriate commit type from the following options: + - feat: A new feature + - fix: A bug fix + - docs: Documentation only changes + - style: Changes that do not affect the meaning of the code + - refactor: A code change that neither fixes a bug nor adds a feature + - perf: A code change that improves performance + - test: Adding missing tests or correcting existing tests + - chore: Changes to the build process or auxiliary tools and libraries + + +2. Adhere to these message guidelines: + - Keep the summary under 70 characters + - Use imperative, present tense (e.g., "add" not "added" or "adds") + - Do not end the summary with a period + - Be concise but descriptive + +3. Format the commit message as follows: + - If a scope is available: (): + - If no scope is available: : + +4 Body Guidelines: + - Add a blank line between summary and body + - Use the body to explain why the change was made, incorporating the user's context, defined in + - Wrap each line in the body at 80 characters maximum + - Break the body into multiple paragraphs if needed + + [Your concise commit message in the specified format] + [blank line] + [Your detailed commit message body] + +Respond ONLY with the commit message text (message and body), nothing else. \ No newline at end of file diff --git a/lib/committer/config/defaults/commit_message_only.prompt b/lib/committer/config/defaults/commit_message_only.prompt new file mode 100644 index 0000000..d28bc8c --- /dev/null +++ b/lib/committer/config/defaults/commit_message_only.prompt @@ -0,0 +1,38 @@ +You are an experienced software developer tasked with creating a commit message based on a git diff. Your goal is to produce a clear, concise, and informative commit message. + +First, carefully analyze the following git diff: + + +{{DIFF}} + + +Here are the available scopes (if any): + + +{{SCOPES}} + + +Please follow these instructions to generate the commit message: + +1. Analyze the git diff and determine the most appropriate commit type from the following options: + - feat: A new feature + - fix: A bug fix + - docs: Documentation only changes + - style: Changes that do not affect the meaning of the code + - refactor: A code change that neither fixes a bug nor adds a feature + - perf: A code change that improves performance + - test: Adding missing tests or correcting existing tests + - chore: Changes to the build process or auxiliary tools and libraries + + +2. Adhere to these message guidelines: + - Keep the summary under 70 characters + - Use imperative, present tense (e.g., "add" not "added" or "adds") + - Do not end the summary with a period + - Be concise but descriptive + +3. Format the commit message as follows: + - If a scope is available: (): + - If no scope is available: : + +Respond ONLY with the commit message line, nothing else. \ No newline at end of file diff --git a/lib/committer/config/writer.rb b/lib/committer/config/writer.rb index da9b4ac..c3888dc 100644 --- a/lib/committer/config/writer.rb +++ b/lib/committer/config/writer.rb @@ -20,7 +20,6 @@ def config_file def setup create_default_config - create_sample_formatting_rules end def write_config_file(file_path, contents) @@ -34,15 +33,6 @@ def write_config_file(file_path, contents) end end - def create_sample_formatting_rules - default_formatting_rules = File.read(File.join(Committer::Config::Constants::DEFAULTS_PATH, - Committer::Config::Constants::FORMATTING_RULES_FILE_NAME)) - formatting_rules_file = File.join(@config_dir, - "#{Committer::Config::Constants::FORMATTING_RULES_FILE_NAME}.sample") - wrote_file = write_config_file(formatting_rules_file, default_formatting_rules) - nil unless wrote_file - end - def create_default_config wrote_file = write_config_file(config_file, Committer::Config::Constants::DEFAULT_CONFIG.to_yaml) return unless wrote_file diff --git a/lib/committer/prompt_templates.rb b/lib/committer/prompt_templates.rb index 501817c..16dbbf8 100644 --- a/lib/committer/prompt_templates.rb +++ b/lib/committer/prompt_templates.rb @@ -2,12 +2,19 @@ module Committer module PromptTemplates - def self.load_formatting_rules - Committer::Config::Accessor.instance.load_formatting_rules + def self.build_prompt(diff, scopes, commit_context) + prompt_template = if commit_context.nil? || commit_context.empty? + Committer::PromptTemplates.build_prompt_summary_only + else + Committer::PromptTemplates.build_prompt_summary_and_body + end + prompt_template + .gsub('{{DIFF}}', diff) + .gsub('{{SCOPES}}', build_scopes_list(scopes)) + .gsub('{{CONTEXT}}', commit_context || '') end - def self.load_scopes - scopes = Committer::Config::Accessor.instance[:scopes] || [] + def self.build_scopes_list(scopes) return 'DO NOT include a scope in your commit message' if scopes.empty? scope_list = "\nScopes:\n#{scopes.map { |s| "- #{s}" }.join("\n")}" @@ -15,56 +22,16 @@ def self.load_scopes "- Choose an appropriate scope from the list above if relevant to the change \n#{scope_list}" end - def self.commit_message_guidelines - <<~PROMPT - #{load_formatting_rules} - - # Formatting rules with body: - - - - - - #{load_scopes} - - # Message Guidelines: - - Keep the summary under 70 characters - - Use imperative, present tense (e.g., "add" not "added" or "adds") - - Do not end the summary with a period - - Be concise but descriptive in the summary - - # Body Guidelines: - - Add a blank line between summary and body - - Use the body to explain why the change was made, incorporating the user's context - - Wrap each line in the body at 80 characters maximum - - Break the body into multiple paragraphs if needed - - Git Diff: - ``` - %s - ``` - PROMPT - end - def self.build_prompt_summary_only - <<~PROMPT - Below is a git diff of staged changes. Please analyze it and create a commit message following the formatting rules format with ONLY a message line (NO body): - - #{commit_message_guidelines} - - Respond ONLY with the commit message line, nothing else. - PROMPT + load_prompt(Committer::Config::Constants::COMMIT_MESSAGE_ONLY_PROMPT_FILE_NAME) end def self.build_prompt_summary_and_body - <<~PROMPT - Below is a git diff of staged changes. Please analyze it and create a commit message following the formatting rules format with a summary line and a detailed body: - - #{commit_message_guidelines} - User's context for this change: %s + load_prompt(Committer::Config::Constants::COMMIT_MESSAGE_AND_BODY_PROMPT_FILE_NAME) + end - Respond ONLY with the commit message text (message and body), nothing else. - PROMPT + def self.load_prompt(file_name) + Committer::Config::Accessor.instance.read_path_prioritized_file(file_name) end end end diff --git a/spec/committer/commit_generator_spec.rb b/spec/committer/commit_generator_spec.rb index 8c838de..ad02827 100644 --- a/spec/committer/commit_generator_spec.rb +++ b/spec/committer/commit_generator_spec.rb @@ -62,7 +62,6 @@ let(:generator) { described_class.new(diff, commit_context) } it 'uses the template with body' do - expect(generator).to receive(:template).and_call_original prompt = generator.build_commit_prompt expect(prompt).to include(commit_context) expect(prompt).to include('Respond ONLY with the commit message text (message and body), nothing else.') @@ -74,7 +73,6 @@ let(:generator) { described_class.new(diff, commit_context) } it 'uses summary-only template when commit context is nil' do - expect(generator).to receive(:template).and_call_original prompt = generator.build_commit_prompt expect(prompt).to include('Respond ONLY with the commit message line, nothing else.') end diff --git a/spec/committer/config/writer_spec.rb b/spec/committer/config/writer_spec.rb index 1c96bf6..9cfe40b 100644 --- a/spec/committer/config/writer_spec.rb +++ b/spec/committer/config/writer_spec.rb @@ -43,14 +43,6 @@ config = YAML.load_file(config_file) expect(config).to eq(Committer::Config::Constants::DEFAULT_CONFIG) end - - it 'writes config sample config rules' do - expect(File.exist?(sample_formatting_rules_file)).to be false - writer.setup - expect(File.exist?(sample_formatting_rules_file)).to be true - contents = File.read(sample_formatting_rules_file) - expect(contents).to include('# Formatting rules for message') - end end describe '#create_default_config' do