Class: Agentilda::Publisher

Inherits:
Object
  • Object
show all
Defined in:
lib/agentilda/publisher.rb

Overview

Turns a finished worktree into a pushed branch and a pull request.

This is the one place the harness reaches off the machine, so it requires --commit, is skipped with --dont-push-anything, and refuses anything it is not certain about. Everything it does is reported before it does it.

Titles follow the convention the whole system joins on:

[002.00](A) Tenancy Households       — a plan's first pull request
[002.00](B) Tenancy Households       — its second

The slug is title-cased from the folder name, so the title reads as a sentence rather than as a path fragment.

Defined Under Namespace

Classes: Publication

Constant Summary collapse

LETTERS =

A..Z, which is more parts than any feature should be split into.

("A".."Z").to_a.freeze

Instance Method Summary collapse

Constructor Details

#initialize(root:, command: TTY::Command.new(printer: :null), base: "main", dry_run: true) ⇒ Publisher

Returns a new instance of Publisher.

Parameters:

  • root (String)

    repository the worktree belongs to

  • command (TTY::Command) (defaults to: TTY::Command.new(printer: :null))
  • base (String) (defaults to: "main")

    the branch pull requests target

  • dry_run (Boolean) (defaults to: true)


42
43
44
45
46
47
# File 'lib/agentilda/publisher.rb', line 42

def initialize(root:, command: TTY::Command.new(printer: :null), base: "main", dry_run: true)
  @root = root
  @command = command
  @base = base
  @dry_run = dry_run
end

Instance Method Details

#auto_letter(subject) ⇒ String

Which part this is. Always a letter, starting at A: a plan that turns out to need only one pull request still reads consistently with every other, and nothing has to be renamed when a second arrives.

Parameters:

Returns:

  • (String)


101
# File 'lib/agentilda/publisher.rb', line 101

def auto_letter(subject) = LETTERS.fetch(subject.pull_requests.size, LETTERS.last)

#git_complaint(error) ⇒ String

git and gh put the useful sentence in stderr, several lines below the command they echo. Reporting only the first line reports "it failed".

Parameters:

  • error (TTY::Command::ExitError)

Returns:

  • (String)


78
79
80
81
82
83
84
# File 'lib/agentilda/publisher.rb', line 78

def git_complaint(error)
  lines = error.message.lines.map(&:strip).reject(&:empty?)
  stderr = lines.find { |l| l.start_with?("stderr:") }
  complaint = stderr&.delete_prefix("stderr:")&.strip

  (complaint.to_s.empty? || complaint == "Nothing written") ? lines.first.to_s : complaint
end

#publish(checkout:, subject:, letter: nil) ⇒ Agentilda::Publisher::Publication

Push one plan's branch and open its pull request.

Parameters:

Returns:



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/agentilda/publisher.rb', line 55

def publish(checkout:, subject:, letter: nil)
  title = title_for(subject, letter)

  unless checkout.dirty?
    return refuse(subject, checkout, title, "nothing to publish — the worktree is unchanged")
  end

  return Publication.new(**base_fields(subject, checkout, title), url: nil, refusal: nil) if @dry_run

  commit(checkout, title)
  push(checkout)
  url = create_pull_request(checkout, subject, title)

  Publication.new(**base_fields(subject, checkout, title), url:, refusal: nil)
rescue TTY::Command::ExitError => e
  refuse(subject, checkout, title, git_complaint(e))
end

#title_for(subject, letter = nil) ⇒ String

The title a plan's next pull request should carry.

Parameters:

Returns:

  • (String)


91
92
93
# File 'lib/agentilda/publisher.rb', line 91

def title_for(subject, letter = nil)
  "[#{subject.feature.ordinal}](#{letter || auto_letter(subject)}) #{subject.feature.title}"
end