Skip to content

Migration Guide: Version 0.9.0

This guide helps you migrate from PromptManager v0.8.x to v0.9.0.

Overview

Version 0.9.0 introduces several breaking changes to improve consistency, performance, and usability. The main changes include:

  • Unified configuration system
  • Improved storage adapter interface
  • Enhanced error handling
  • Streamlined directive processing

Breaking Changes

1. Configuration System Changes

Old Configuration (v0.8.x)

PromptManager.setup do |config|
  config.prompts_directory = '/path/to/prompts'
  config.enable_caching = true
  config.cache_duration = 300
  config.default_storage = :filesystem
end

New Configuration (v0.9.0)

PromptManager.configure do |config|
  config.storage = PromptManager::Storage::FileSystemAdapter.new(
    prompts_dir: '/path/to/prompts'
  )
  config.cache_prompts = true
  config.cache_ttl = 300
end

Migration Steps

  1. Replace PromptManager.setup with PromptManager.configure
  2. Replace config.prompts_directory with explicit storage adapter configuration
  3. Update cache configuration keys:
  4. enable_cachingcache_prompts
  5. cache_durationcache_ttl

2. Storage Adapter Interface

Old Interface (v0.8.x)

class CustomAdapter
  def get_prompt(id)
    # Old method name
  end

  def save_prompt(id, content)
    # Old method name
  end

  def prompt_exists?(id)
    # Old method name
  end
end

New Interface (v0.9.0)

class CustomAdapter < PromptManager::Storage::Base
  def read(prompt_id)
    # New method name and inheritance requirement
  end

  def write(prompt_id, content)
    # New method name
  end

  def exist?(prompt_id)
    # New method name
  end

  def delete(prompt_id)
    # New required method
  end

  def list
    # New required method
  end
end

Migration Steps

  1. Make your adapter inherit from PromptManager::Storage::Base
  2. Rename methods:
  3. get_promptread
  4. save_promptwrite
  5. prompt_exists?exist?
  6. Implement new required methods: delete and list
  7. Update method signatures to use prompt_id parameter name

3. Error Class Changes

Old Error Classes (v0.8.x)

begin
  prompt.render
rescue PromptManager::PromptMissingError => e
  # Handle missing prompt
rescue PromptManager::ParameterMissingError => e
  # Handle missing parameters
end

New Error Classes (v0.9.0)

begin
  prompt.render
rescue PromptManager::PromptNotFoundError => e
  # Handle missing prompt
rescue PromptManager::MissingParametersError => e
  # Handle missing parameters
  puts "Missing: #{e.missing_parameters.join(', ')}"
end

Migration Steps

  1. Update exception class names:
  2. PromptMissingErrorPromptNotFoundError
  3. ParameterMissingErrorMissingParametersError
  4. Use the new missing_parameters method for detailed parameter information

4. Prompt Initialization

Old Initialization (v0.8.x)

prompt = PromptManager::Prompt.new('prompt_id')
prompt.storage_adapter = custom_adapter

New Initialization (v0.9.0)

prompt = PromptManager::Prompt.new(
  id: 'prompt_id',
  storage: custom_adapter
)

Migration Steps

  1. Use keyword arguments in Prompt.new
  2. Pass storage adapter during initialization instead of setting it afterward

Feature Updates

1. Enhanced Parameter Support

New Features

  • Nested parameter access: [USER.NAME], [ORDER.ITEMS.0.NAME]
  • Array parameter formatting
  • Better error messages for missing parameters

Migration Recommendation

Review your prompts for any parameter names that might conflict with the new nested syntax.

2. Improved Directive Processing

Changes

  • More robust //include processing
  • Better error handling for circular includes
  • New directive registration system

Migration Steps

No changes required for basic //include usage. Custom directive implementations may need updates.

3. Enhanced Caching

New Caching Options

PromptManager.configure do |config|
  config.cache_prompts = true
  config.cache_ttl = 3600
  config.cache_store = ActiveSupport::Cache::RedisStore.new(
    url: ENV['REDIS_URL']
  )
end

Database Schema Changes (ActiveRecord Adapter)

Schema Updates Required

If you're using the ActiveRecord adapter, run this migration:

class UpdatePromptsForPromptManagerV09 < ActiveRecord::Migration[7.0]
  def change
    # Add new columns
    add_column :prompts, :metadata, :json, default: {}
    add_column :prompts, :version, :integer, default: 1
    add_column :prompts, :created_by, :string
    add_column :prompts, :updated_by, :string

    # Add indexes for better performance
    add_index :prompts, :metadata, using: :gin
    add_index :prompts, :version
    add_index :prompts, :updated_at

    # Update existing records
    execute <<-SQL
      UPDATE prompts 
      SET metadata = '{}', version = 1 
      WHERE metadata IS NULL OR version IS NULL
    SQL
  end

  def down
    remove_column :prompts, :metadata
    remove_column :prompts, :version  
    remove_column :prompts, :created_by
    remove_column :prompts, :updated_by
  end
end

Step-by-Step Migration Process

1. Update Dependencies

# Gemfile
gem 'prompt_manager', '~> 0.9.0'

Run bundle update prompt_manager

2. Update Configuration

# Before (v0.8.x)
PromptManager.setup do |config|
  config.prompts_directory = Rails.root.join('app', 'prompts')
  config.enable_caching = true
  config.cache_duration = 1800
end

# After (v0.9.0)
PromptManager.configure do |config|
  config.storage = PromptManager::Storage::FileSystemAdapter.new(
    prompts_dir: Rails.root.join('app', 'prompts')
  )
  config.cache_prompts = true
  config.cache_ttl = 1800
end

3. Update Custom Storage Adapters

# Before (v0.8.x)
class RedisAdapter
  def get_prompt(id)
    @redis.get("prompt:#{id}")
  end

  def save_prompt(id, content)
    @redis.set("prompt:#{id}", content)
  end

  def prompt_exists?(id)
    @redis.exists?("prompt:#{id}")
  end
end

# After (v0.9.0)  
class RedisAdapter < PromptManager::Storage::Base
  def read(prompt_id)
    content = @redis.get(key_for(prompt_id))
    raise PromptManager::PromptNotFoundError.new("Prompt '#{prompt_id}' not found") unless content
    content
  end

  def write(prompt_id, content)
    @redis.set(key_for(prompt_id), content)
    true
  end

  def exist?(prompt_id)
    @redis.exists?(key_for(prompt_id)) > 0
  end

  def delete(prompt_id)
    @redis.del(key_for(prompt_id)) > 0
  end

  def list
    keys = @redis.keys("prompts:*")
    keys.map { |key| key.sub('prompts:', '') }
  end

  private

  def key_for(prompt_id)
    "prompts:#{prompt_id}"
  end
end

4. Update Error Handling

# Before (v0.8.x)
begin
  result = prompt.render(params)
rescue PromptManager::PromptMissingError
  render json: { error: 'Prompt not found' }, status: 404
rescue PromptManager::ParameterMissingError => e
  render json: { error: 'Missing parameters' }, status: 400
end

# After (v0.9.0)
begin
  result = prompt.render(params)
rescue PromptManager::PromptNotFoundError
  render json: { error: 'Prompt not found' }, status: 404
rescue PromptManager::MissingParametersError => e
  render json: { 
    error: 'Missing parameters',
    missing: e.missing_parameters 
  }, status: 400
end

5. Update Prompt Creation

# Before (v0.8.x)
prompt = PromptManager::Prompt.new('welcome_email')
prompt.enable_erb = true

# After (v0.9.0)
prompt = PromptManager::Prompt.new(
  id: 'welcome_email',
  erb_flag: true
)

6. Run Database Migrations (if using ActiveRecord)

rails generate migration UpdatePromptsForPromptManagerV09
# Edit the migration file with the schema changes shown above
rails db:migrate

7. Update Tests

# Update test setup
RSpec.configure do |config|
  config.before(:each) do
    # Clear configuration between tests
    PromptManager.reset_configuration!

    # Setup test configuration
    PromptManager.configure do |config|
      config.storage = PromptManager::Storage::FileSystemAdapter.new(
        prompts_dir: 'spec/fixtures/prompts'
      )
    end
  end
end

Validation & Testing

1. Configuration Validation

Add this to verify your configuration:

# In your application's initialization
begin
  PromptManager.validate_configuration!
  puts "✅ PromptManager configuration is valid"
rescue PromptManager::ConfigurationError => e
  puts "❌ Configuration error: #{e.message}"
  exit 1
end

2. Migration Test Script

Create a test script to validate the migration:

#!/usr/bin/env ruby

require 'prompt_manager'

# Test basic functionality
begin
  PromptManager.configure do |config|
    config.storage = PromptManager::Storage::FileSystemAdapter.new(
      prompts_dir: 'test_prompts'
    )
  end

  # Create test prompt
  prompt = PromptManager::Prompt.new(id: 'test')
  prompt.write('Hello [NAME]!')

  # Test rendering
  result = prompt.render(name: 'World')

  if result == 'Hello World!'
    puts "✅ Migration successful - basic functionality works"
  else
    puts "❌ Migration failed - unexpected result: #{result}"
  end

  # Cleanup
  prompt.delete

rescue => e
  puts "❌ Migration failed with error: #{e.message}"
  puts e.backtrace
end

Rollback Plan

If you need to rollback to v0.8.x:

  1. Update Gemfile: gem 'prompt_manager', '~> 0.8.0'
  2. Run: bundle install
  3. Revert configuration changes to the old format
  4. Revert database migrations (if using ActiveRecord):
    rails db:rollback STEP=1
    

Getting Help

  • Documentation: Check the updated documentation at https://madbomber.github.io/prompt_manager
  • GitHub Issues: Report migration issues at https://github.com/MadBomber/prompt_manager/issues
  • Discussions: Ask questions in GitHub Discussions

Post-Migration Checklist

  • Updated Gemfile and ran bundle install
  • Updated configuration format
  • Updated custom storage adapters (if any)
  • Updated error handling code
  • Ran database migrations (if using ActiveRecord)
  • Updated tests
  • Validated configuration with test script
  • Deployed to staging and tested thoroughly
  • Updated documentation and team

Need help? The migration should be straightforward for most applications. If you encounter issues, please open a GitHub issue with details about your setup and the specific problems you're experiencing.