Class: Ace::Git::Worktree::Models::WorktreeConfig

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/git/worktree/models/worktree_config.rb

Overview

Configuration model for worktree settings

Represents the configuration loaded from .ace/git/worktree.yml with defaults, validation, and accessors for all configuration options.

Examples:

Create configuration with defaults

config = WorktreeConfig.new
config.root_path # => ".ace-wt"

Load from configuration hash

config = WorktreeConfig.new({
  "git" => {
    "worktree" => {
      "root_path" => "~/worktrees",
      "mise_trust_auto" => false
    }
  }
})

Constant Summary collapse

DEFAULT_CONFIG =

Default configuration values

{
  "root_path" => ".ace-wt",
  "auto_navigate" => true,
  "tmux" => false,
  "mise_trust_auto" => true,
  "task" => {
    "directory_format" => "t.{task_id}",
    "branch_format" => "{id}-{slug}",
    "auto_mark_in_progress" => true,
    "auto_commit_task" => true,
    "auto_push_task" => true,
    "push_remote" => "origin",
    "commit_message_format" => "chore({task_id}): mark as in-progress, creating worktree for {slug}",
    "add_worktree_metadata" => true,
    "auto_setup_upstream" => false,
    "auto_create_pr" => false,
    "pr_title_format" => "{id} - {slug}",
    "create_current_symlink" => true,
    "current_symlink_name" => "_current"
  },
  "pr" => {
    "directory_format" => "ace-pr-{number}",
    "branch_format" => "pr-{number}-{slug}",
    "remote_name" => "origin",
    "fetch_before_create" => true,
    "configure_push_for_mismatch" => true
  },
  "branch" => {
    "fetch_if_remote" => true,
    "auto_detect_remote" => true
  },
  "cleanup" => {
    "on_merge" => false,
    "on_delete" => true
  },
  "bootstrap" => {
    "command" => nil,
    "working_dir" => ".",
    "timeout" => 60,
    "policy" => "required",
    "env" => {}
  },
  "hooks" => {
    "after_create" => []
  }
}.freeze
CONFIG_NAMESPACE =

Configuration namespace paths

["git", "worktree"].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_hash = {}, project_root = Dir.pwd) ⇒ WorktreeConfig

Initialize a new WorktreeConfig

Parameters:

  • config_hash (Hash) (defaults to: {})

    Configuration hash (typically from ace-core)

  • project_root (String) (defaults to: Dir.pwd)

    Project root directory for relative paths



85
86
87
88
89
90
91
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 85

def initialize(config_hash = {}, project_root = Dir.pwd)
  @project_root = project_root
  @raw_config = extract_worktree_config(config_hash)
  @merged_config = merge_with_defaults(@raw_config)

  initialize_attributes
end

Instance Attribute Details

#auto_navigateObject (readonly)

Returns the value of attribute auto_navigate.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def auto_navigate
  @auto_navigate
end

#bootstrap_configObject (readonly)

Returns the value of attribute bootstrap_config.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def bootstrap_config
  @bootstrap_config
end

#branch_configObject (readonly)

Returns the value of attribute branch_config.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def branch_config
  @branch_config
end

#cleanup_configObject (readonly)

Returns the value of attribute cleanup_config.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def cleanup_config
  @cleanup_config
end

#hooks_configObject (readonly)

Returns the value of attribute hooks_config.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def hooks_config
  @hooks_config
end

#mise_trust_autoObject (readonly)

Returns the value of attribute mise_trust_auto.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def mise_trust_auto
  @mise_trust_auto
end

#pr_configObject (readonly)

Returns the value of attribute pr_config.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def pr_config
  @pr_config
end

#root_pathObject (readonly)

Returns the value of attribute root_path.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def root_path
  @root_path
end

#task_configObject (readonly)

Returns the value of attribute task_config.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def task_config
  @task_config
end

#tmuxObject (readonly)

Returns the value of attribute tmux.



79
80
81
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 79

def tmux
  @tmux
end

Instance Method Details

#absolute_root_pathString

Get the root path for worktrees (expanded and absolute)

Returns:

  • (String)

    Absolute path to worktree root directory



220
221
222
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 220

def absolute_root_path
  @absolute_root_path ||= expand_root_path
end

#add_worktree_metadata?Boolean

Check if worktree metadata should be added to tasks

Returns:

  • (Boolean)

    true if metadata should be added



166
167
168
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 166

def add_worktree_metadata?
  @task_config["add_worktree_metadata"]
end

#after_create_hooksArray<Hash>

Get after-create hooks configuration

Returns:

  • (Array<Hash>)

    Array of hook definitions



241
242
243
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 241

def after_create_hooks
  @hooks_config["after_create"] || []
end

#auto_commit_task?Boolean

Check if task changes should be committed automatically

Returns:

  • (Boolean)

    true if task changes should be committed



138
139
140
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 138

def auto_commit_task?
  @task_config["auto_commit_task"]
end

#auto_create_pr?Boolean

Check if draft PR should be created automatically

Returns:

  • (Boolean)

    true if auto PR creation is enabled



180
181
182
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 180

def auto_create_pr?
  @task_config["auto_create_pr"]
end

#auto_mark_in_progress?Boolean

Check if tasks should be marked as in-progress automatically

Returns:

  • (Boolean)

    true if tasks should be marked in-progress



131
132
133
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 131

def auto_mark_in_progress?
  @task_config["auto_mark_in_progress"]
end

#auto_navigate?Boolean

Check if auto-navigation should be performed

Returns:

  • (Boolean)

    true if auto-navigation should be performed



110
111
112
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 110

def auto_navigate?
  @auto_navigate
end

#auto_push_task?Boolean

Check if task changes should be pushed automatically

Returns:

  • (Boolean)

    true if task changes should be pushed



145
146
147
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 145

def auto_push_task?
  @task_config["auto_push_task"] != false
end

#auto_setup_upstream?Boolean

Check if new worktree branch should be pushed to remote with upstream tracking

Returns:

  • (Boolean)

    true if upstream setup is enabled



173
174
175
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 173

def auto_setup_upstream?
  @task_config["auto_setup_upstream"]
end

#bootstrapHash

Get bootstrap configuration

Returns:

  • (Hash)

    Bootstrap configuration hash



389
390
391
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 389

def bootstrap
  @bootstrap_config
end

#bootstrap_configured?Boolean

Check if bootstrap is configured with a command

Returns:

  • (Boolean)

    true if bootstrap command is set



396
397
398
399
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 396

def bootstrap_configured?
  cmd = @bootstrap_config["command"]
  !cmd.nil? && !cmd.to_s.strip.empty?
end

#branch_formatString

Get the branch format for task-based worktrees

Returns:

  • (String)

    Branch format template



103
104
105
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 103

def branch_format
  @task_config["branch_format"]
end

#cleanup_on_delete?Boolean

Check if worktrees should be cleaned up on branch delete

Returns:

  • (Boolean)

    true if cleanup on delete



234
235
236
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 234

def cleanup_on_delete?
  @cleanup_config["on_delete"]
end

#cleanup_on_merge?Boolean

Check if worktrees should be cleaned up on branch merge

Returns:

  • (Boolean)

    true if cleanup on merge



227
228
229
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 227

def cleanup_on_merge?
  @cleanup_config["on_merge"]
end

#commit_message_formatString

Get the commit message format for task updates

Returns:

  • (String)

    Commit message template



159
160
161
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 159

def commit_message_format
  @task_config["commit_message_format"]
end

#configure_push_for_mismatch?Boolean

Check if push should be configured for PR branches with name mismatches

Returns:

  • (Boolean)

    true if push should be configured for mismatched branch names



248
249
250
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 248

def configure_push_for_mismatch?
  @pr_config["configure_push_for_mismatch"]
end

#create_current_symlink?Boolean

Check if _current symlink should be created

Returns:

  • (Boolean)

    true if symlink should be created



194
195
196
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 194

def create_current_symlink?
  @task_config["create_current_symlink"] != false
end

Get the name for the _current symlink

Returns:

  • (String)

    Symlink name (default: "_current")



201
202
203
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 201

def current_symlink_name
  @task_config["current_symlink_name"] || "_current"
end

#directory_formatString

Get the directory format for task-based worktrees

Returns:

  • (String)

    Directory format template



96
97
98
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 96

def directory_format
  @task_config["directory_format"]
end

#format_branch(task_data) ⇒ String

Format a branch name using task data

Examples:

config.format_branch(task) # => "081-fix-authentication-bug"

Parameters:

  • task_data (Hash)

    Task data hash from ace-task

Returns:

  • (String)

    Formatted branch name



286
287
288
289
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 286

def format_branch(task_data)
  template = branch_format
  apply_template_variables(template, task_data)
end

#format_commit_message(task_data) ⇒ String

Format a commit message for task updates

Examples:

config.format_commit_message(task) # => "chore(task-081): mark as in-progress, creating worktree"

Parameters:

  • task_data (Hash)

    Task data hash from ace-task

Returns:

  • (String)

    Formatted commit message



298
299
300
301
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 298

def format_commit_message(task_data)
  template = commit_message_format
  apply_template_variables(template, task_data)
end

#format_directory(task_data, counter = nil) ⇒ String

Format a directory path using task data

Examples:

config.format_directory(task) # => "t.081"
config.format_directory(task, 2) # => "t.081-2"

Parameters:

  • task_data (Hash)

    Task data hash from ace-task

  • counter (Integer, nil) (defaults to: nil)

    Counter for multiple worktrees of same task

Returns:

  • (String)

    Formatted directory path



269
270
271
272
273
274
275
276
277
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 269

def format_directory(task_data, counter = nil)
  template = directory_format
  formatted = apply_template_variables(template, task_data)

  # Add counter if provided
  formatted = "#{formatted}-#{counter}" if counter

  formatted
end

#format_pr_title(task_data) ⇒ String

Format a PR title using task data

Examples:

config.format_pr_title(task) # => "081 - fix-authentication-bug"

Parameters:

  • task_data (Hash)

    Task data hash from ace-task

Returns:

  • (String)

    Formatted PR title



212
213
214
215
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 212

def format_pr_title(task_data)
  template = pr_title_format
  apply_template_variables(template, task_data)
end

#hooks_enabled?Boolean

Check if hooks are configured

Returns:

  • (Boolean)

    true if any hooks are configured



255
256
257
258
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 255

def hooks_enabled?
  hooks = after_create_hooks
  hooks.is_a?(Array) && hooks.any?
end

#mise_trust_auto?Boolean

Check if mise should automatically trust worktree directories

Returns:

  • (Boolean)

    true if mise auto-trust is enabled



124
125
126
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 124

def mise_trust_auto?
  @mise_trust_auto
end

#pr_title_formatString

Get the PR title format template

Returns:

  • (String)

    PR title format template



187
188
189
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 187

def pr_title_format
  @task_config["pr_title_format"]
end

#push_remoteString

Get the remote for pushing task changes

Returns:

  • (String)

    Remote name (default: "origin")



152
153
154
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 152

def push_remote
  @task_config["push_remote"] || "origin"
end

#tmux?Boolean

Check if tmux session should be launched after worktree creation

Returns:

  • (Boolean)

    true if tmux launch is enabled



117
118
119
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 117

def tmux?
  @tmux
end

#to_hHash

Get configuration as a hash

Returns:

  • (Hash)

    Configuration hash



374
375
376
377
378
379
380
381
382
383
384
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 374

def to_h
  {
    root_path: root_path,
    auto_navigate: auto_navigate?,
    mise_trust_auto: mise_trust_auto?,
    task: @task_config.dup,
    bootstrap: @bootstrap_config.dup,
    cleanup: @cleanup_config.dup,
    hooks: @hooks_config.dup
  }
end

#validateArray<String>

Validate configuration settings

Returns:

  • (Array<String>)

    Array of validation error messages (empty if valid)



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/ace/git/worktree/models/worktree_config.rb', line 306

def validate
  errors = []

  # Validate root_path
  unless root_path.is_a?(String) && !root_path.empty?
    errors << "root_path must be a non-empty string"
  end

  # Validate task template formats
  unless directory_format.is_a?(String) && !directory_format.empty?
    errors << "task.directory_format must be a non-empty string"
  end

  unless branch_format.is_a?(String) && !branch_format.empty?
    errors << "task.branch_format must be a non-empty string"
  end

  # Validate PR template formats
  pr_dir_format = @pr_config["directory_format"]
  unless pr_dir_format.is_a?(String) && !pr_dir_format.empty?
    errors << "pr.directory_format must be a non-empty string"
  end

  pr_branch_format = @pr_config["branch_format"]
  unless pr_branch_format.is_a?(String) && !pr_branch_format.empty?
    errors << "pr.branch_format must be a non-empty string"
  end

  # Validate template variables for task configuration
  task_templates = {
    "task.directory_format" => {template: directory_format, valid_vars: %w[task_id id slug]},
    "task.branch_format" => {template: branch_format, valid_vars: %w[id slug task_id]},
    "task.commit_message_format" => {template: commit_message_format, valid_vars: %w[task_id slug id]}
  }

  task_templates.each do |name, config|
    invalid_vars = find_invalid_template_variables(config[:template], config[:valid_vars])
    if invalid_vars.any?
      errors << "#{name} contains invalid variables: #{invalid_vars.join(", ")}. Valid variables: #{config[:valid_vars].map { |v| "{#{v}}" }.join(", ")}"
    end

    # Warn if template has no variables (except for commit_message_format which is optional)
    unless name == "task.commit_message_format"
      if config[:template] && !config[:template].match?(/\{[^}]+\}/)
        errors << "#{name} should include at least one template variable from: #{config[:valid_vars].map { |v| "{#{v}}" }.join(", ")}"
      end
    end
  end

  # Validate template variables for PR configuration
  pr_templates = {
    "pr.directory_format" => {template: pr_dir_format, valid_vars: %w[number slug title base_branch]},
    "pr.branch_format" => {template: pr_branch_format, valid_vars: %w[number slug title base_branch]}
  }

  pr_templates.each do |name, config|
    invalid_vars = find_invalid_template_variables(config[:template], config[:valid_vars])
    if invalid_vars.any?
      errors << "#{name} contains invalid variables: #{invalid_vars.join(", ")}. Valid variables: #{config[:valid_vars].map { |v| "{#{v}}" }.join(", ")}"
    end
  end

  errors
end