Class: Agentilda::PullRequests

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

Overview

Extracts the pull request roll-up from a plan folder.

Constant Summary collapse

/\[((?:\\.|[^\]\\])+)\]\((https?:[^)\s]+)\)/
STATES =

Canonical wording for the states we recognise, most specific first.

[
  [/\bclosed\b|\bunmerged\b|\babandoned\b/i, "Closed 🔴"],
  [/\bmerged\b/i, "Merged 🟣"],
  [/\bdraft\b|\bwip\b/i, "WIP 🟡"],
  [/\bopen\b/i, "Open 🟡"]
].freeze
CANDIDATES =

Filenames that may hold the table.

%w[pull-requests.md pull_requests.md prs.md].freeze
FILENAME =

The file this class writes, and the first one it looks for.

CANDIDATES.first

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir:) ⇒ PullRequests

Returns a new instance of PullRequests.

Parameters:

  • dir (String)

    absolute path to the plan folder



114
115
116
# File 'lib/agentilda/pull_request.rb', line 114

def initialize(dir:)
  @dir = dir
end

Class Method Details

.describe(pr) ⇒ String

Parameters:

  • pr (Hash)

Returns:

  • (String)


82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/agentilda/pull_request.rb', line 82

def self.describe(pr)
  body = pr[:body].to_s.strip
  body = "_No description was written on the pull request._" if body.empty?

  <<~MARKDOWN
    ### ##{pr[:number]} — #{pr[:title]}

    #{pr[:url]}

    #{body}
  MARKDOWN
end

.escape(text) ⇒ String

Three characters have to survive a round trip through a table cell.

A | ends the cell, and a title containing one is not unusual — "fix: guard against a || b".

[ and ] are newer and cost more. Every title this tool writes now opens with a plan number, so the row reads [[013.00] Ship it](url) — and a markdown link whose text starts with [ does not parse. The title came back with the URL glued to it and url came back nil, which is not a cosmetic loss: it is every pull request link on the page, and the attachment on every Linear issue.

Parameters:

  • text (String)

Returns:

  • (String)


109
110
111
# File 'lib/agentilda/pull_request.rb', line 109

def self.escape(text)
  text.to_s.gsub(/([\[\]|])/) { "\\#{$1}" }.gsub(/\s+/, " ").strip
end

.render(prs) ⇒ String

Render pull-requests.md for a set of pull requests fetched from GitHub.

The table is what #parse reads back and what the state machine judges a folder by. The descriptions below it are for a reader — human or agent — synthesizing a specification from work that already shipped: the table says which pull requests, the bodies say what they did, and a retroactive spec.md cannot be written from numbers alone.

Prose after the table is ignored by the parser, so the two can coexist in one file rather than needing a scratch file the folder rules forbid.

Parameters:

  • prs (Array<Hash>)

    {number:, title:, url:, state:, body:}

Returns:

  • (String)


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/agentilda/pull_request.rb', line 62

def self.render(prs)
  rows = prs.map { |pr|
    "| #{pr[:number]} | [#{escape(pr[:title])}](#{pr[:url]}) | #{pr[:state]} |"
  }

  <<~MARKDOWN
    # Pull Requests

    | Pull Request Number | Pull Request Name | Status |
    | ------------------: | :---------------- | -----: |
    #{rows.join("\n")}

    ## What these pull requests did

    #{prs.map { |pr| describe(pr) }.join("\n")}
  MARKDOWN
end

Instance Method Details

#allArray<Agentilda::PullRequest>

Returns possibly empty.

Returns:



119
# File 'lib/agentilda/pull_request.rb', line 119

def all = @all ||= parse