2026-07-12 19:54:08 +00:00
|
|
|
module Backlog
|
|
|
|
|
# Validates and classifies tracker keys (the value written to
|
|
|
|
|
# `.cc-os/config`'s `tracker` field) and parses `git remote -v` output to
|
|
|
|
|
# detect a Forgejo/GitHub remote. Pure — no filesystem, no network.
|
|
|
|
|
class Tracker
|
|
|
|
|
DEFAULT_FORGEJO_HOST = "forgejo.swansoncloud.com"
|
|
|
|
|
|
Retire Planka: os-backlog reworked to git-issues-only (ADR-0042)
Executes OpenSpec change retire-planka-git-issues-only (archived, 25/25 tasks):
- os-backlog v0.3.0: Planka lib/CLI/agents deleted; issue-create/issues
helpers (tea/gh/repo-file dispatch); ten-label taxonomy, human-only next
- planka: rejected fail-soft citing ADR-0042 in tracker grammar,
config-write, and the os-status check
- Skills, SessionStart note (~687 -> ~444 tokens), /to-issues, os-status fix
rewritten to the single-tracker model
- All boards snapshotted + pg-dumped (ovh-vps ~/planka-final-snapshot-2026-07-16);
cards migrated to jared/cc-os#61-70, jared/ops#1-21, jared/llf-schema#7-10
- Planka server decommissioned; planka gem repo archived read-only
- Delta specs synced to openspec/specs/ (issue-backlog, issue-state-labels)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014HWNfGWoWnhrub4EJa1M1Y
2026-07-16 19:48:40 +00:00
|
|
|
# ADR-0042 retired Planka: the tracker grammar is exactly these three
|
|
|
|
|
# forms. `planka:` is deliberately absent — it is rejected, not merely
|
|
|
|
|
# unmatched (see config-write and os-status's tracker-configured check).
|
2026-07-12 19:54:08 +00:00
|
|
|
FORMATS = {
|
|
|
|
|
forgejo: %r{\Aforgejo:[\w.-]+/[\w.-]+\z},
|
|
|
|
|
github: %r{\Agithub:[\w.-]+/[\w.-]+\z},
|
|
|
|
|
repo: /\Arepo:.+\z/
|
|
|
|
|
}.freeze
|
|
|
|
|
|
Retire Planka: os-backlog reworked to git-issues-only (ADR-0042)
Executes OpenSpec change retire-planka-git-issues-only (archived, 25/25 tasks):
- os-backlog v0.3.0: Planka lib/CLI/agents deleted; issue-create/issues
helpers (tea/gh/repo-file dispatch); ten-label taxonomy, human-only next
- planka: rejected fail-soft citing ADR-0042 in tracker grammar,
config-write, and the os-status check
- Skills, SessionStart note (~687 -> ~444 tokens), /to-issues, os-status fix
rewritten to the single-tracker model
- All boards snapshotted + pg-dumped (ovh-vps ~/planka-final-snapshot-2026-07-16);
cards migrated to jared/cc-os#61-70, jared/ops#1-21, jared/llf-schema#7-10
- Planka server decommissioned; planka gem repo archived read-only
- Delta specs synced to openspec/specs/ (issue-backlog, issue-state-labels)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014HWNfGWoWnhrub4EJa1M1Y
2026-07-16 19:48:40 +00:00
|
|
|
# @return [Boolean] true if value matches one of the three valid formats
|
2026-07-12 19:54:08 +00:00
|
|
|
def self.valid?(value)
|
|
|
|
|
!kind(value).nil?
|
|
|
|
|
end
|
|
|
|
|
|
Retire Planka: os-backlog reworked to git-issues-only (ADR-0042)
Executes OpenSpec change retire-planka-git-issues-only (archived, 25/25 tasks):
- os-backlog v0.3.0: Planka lib/CLI/agents deleted; issue-create/issues
helpers (tea/gh/repo-file dispatch); ten-label taxonomy, human-only next
- planka: rejected fail-soft citing ADR-0042 in tracker grammar,
config-write, and the os-status check
- Skills, SessionStart note (~687 -> ~444 tokens), /to-issues, os-status fix
rewritten to the single-tracker model
- All boards snapshotted + pg-dumped (ovh-vps ~/planka-final-snapshot-2026-07-16);
cards migrated to jared/cc-os#61-70, jared/ops#1-21, jared/llf-schema#7-10
- Planka server decommissioned; planka gem repo archived read-only
- Delta specs synced to openspec/specs/ (issue-backlog, issue-state-labels)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014HWNfGWoWnhrub4EJa1M1Y
2026-07-16 19:48:40 +00:00
|
|
|
# @return [Symbol, nil] :forgejo / :github / :repo, or nil if invalid
|
2026-07-12 19:54:08 +00:00
|
|
|
def self.kind(value)
|
|
|
|
|
return nil unless value.is_a?(String)
|
|
|
|
|
|
|
|
|
|
FORMATS.each { |name, pattern| return name if value.match?(pattern) }
|
|
|
|
|
nil
|
|
|
|
|
end
|
|
|
|
|
|
2026-07-13 13:18:45 +00:00
|
|
|
# Where /to-issues output (spec slices) should be published, given the
|
Retire Planka: os-backlog reworked to git-issues-only (ADR-0042)
Executes OpenSpec change retire-planka-git-issues-only (archived, 25/25 tasks):
- os-backlog v0.3.0: Planka lib/CLI/agents deleted; issue-create/issues
helpers (tea/gh/repo-file dispatch); ten-label taxonomy, human-only next
- planka: rejected fail-soft citing ADR-0042 in tracker grammar,
config-write, and the os-status check
- Skills, SessionStart note (~687 -> ~444 tokens), /to-issues, os-status fix
rewritten to the single-tracker model
- All boards snapshotted + pg-dumped (ovh-vps ~/planka-final-snapshot-2026-07-16);
cards migrated to jared/cc-os#61-70, jared/ops#1-21, jared/llf-schema#7-10
- Planka server decommissioned; planka gem repo archived read-only
- Delta specs synced to openspec/specs/ (issue-backlog, issue-state-labels)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014HWNfGWoWnhrub4EJa1M1Y
2026-07-16 19:48:40 +00:00
|
|
|
# repo's tracker key. One tracker holds both state and specs (ADR-0042):
|
|
|
|
|
# forgejo:/github: keys route spec slices to that git issue tracker;
|
|
|
|
|
# repo:<path> routes to the in-repo issue-file convention; nil or any
|
|
|
|
|
# invalid key (including retired `planka:` values) is :unrouted.
|
2026-07-13 13:18:45 +00:00
|
|
|
#
|
Retire Planka: os-backlog reworked to git-issues-only (ADR-0042)
Executes OpenSpec change retire-planka-git-issues-only (archived, 25/25 tasks):
- os-backlog v0.3.0: Planka lib/CLI/agents deleted; issue-create/issues
helpers (tea/gh/repo-file dispatch); ten-label taxonomy, human-only next
- planka: rejected fail-soft citing ADR-0042 in tracker grammar,
config-write, and the os-status check
- Skills, SessionStart note (~687 -> ~444 tokens), /to-issues, os-status fix
rewritten to the single-tracker model
- All boards snapshotted + pg-dumped (ovh-vps ~/planka-final-snapshot-2026-07-16);
cards migrated to jared/cc-os#61-70, jared/ops#1-21, jared/llf-schema#7-10
- Planka server decommissioned; planka gem repo archived read-only
- Delta specs synced to openspec/specs/ (issue-backlog, issue-state-labels)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014HWNfGWoWnhrub4EJa1M1Y
2026-07-16 19:48:40 +00:00
|
|
|
# @return [Symbol] :git_issues | :repo_files | :unrouted
|
2026-07-13 13:18:45 +00:00
|
|
|
def self.issues_destination(value)
|
|
|
|
|
case kind(value)
|
|
|
|
|
when :forgejo, :github then :git_issues
|
Retire Planka: os-backlog reworked to git-issues-only (ADR-0042)
Executes OpenSpec change retire-planka-git-issues-only (archived, 25/25 tasks):
- os-backlog v0.3.0: Planka lib/CLI/agents deleted; issue-create/issues
helpers (tea/gh/repo-file dispatch); ten-label taxonomy, human-only next
- planka: rejected fail-soft citing ADR-0042 in tracker grammar,
config-write, and the os-status check
- Skills, SessionStart note (~687 -> ~444 tokens), /to-issues, os-status fix
rewritten to the single-tracker model
- All boards snapshotted + pg-dumped (ovh-vps ~/planka-final-snapshot-2026-07-16);
cards migrated to jared/cc-os#61-70, jared/ops#1-21, jared/llf-schema#7-10
- Planka server decommissioned; planka gem repo archived read-only
- Delta specs synced to openspec/specs/ (issue-backlog, issue-state-labels)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014HWNfGWoWnhrub4EJa1M1Y
2026-07-16 19:48:40 +00:00
|
|
|
when :repo then :repo_files
|
|
|
|
|
else :unrouted
|
2026-07-13 13:18:45 +00:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2026-07-12 19:54:08 +00:00
|
|
|
# Parse the first remote line of `git remote -v` output and classify it
|
|
|
|
|
# as a Forgejo or GitHub remote (or :unknown for anything else).
|
|
|
|
|
#
|
|
|
|
|
# @param output [String] raw `git remote -v` output
|
|
|
|
|
# @param forgejo_host [String] hostname that identifies the user's
|
|
|
|
|
# self-hosted Forgejo instance
|
|
|
|
|
# @return [Hash, nil] {kind:, host:, owner:, repo:}, or nil if no remote
|
|
|
|
|
# URL could be parsed
|
|
|
|
|
def self.parse_remote(output, forgejo_host: DEFAULT_FORGEJO_HOST)
|
|
|
|
|
line = output.to_s.lines.first
|
|
|
|
|
return nil unless line
|
|
|
|
|
|
|
|
|
|
url = line.split(/\s+/)[1]
|
|
|
|
|
return nil unless url
|
|
|
|
|
|
|
|
|
|
host, path = split_host_path(url)
|
|
|
|
|
return nil unless host && path
|
|
|
|
|
|
|
|
|
|
owner, repo = path.sub(/\.git\z/, "").split("/").last(2)
|
|
|
|
|
return nil unless owner && repo
|
|
|
|
|
|
|
|
|
|
kind = if host == forgejo_host
|
|
|
|
|
:forgejo
|
|
|
|
|
elsif host == "github.com"
|
|
|
|
|
:github
|
|
|
|
|
else
|
|
|
|
|
:unknown
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
{ kind: kind, host: host, owner: owner, repo: repo }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def self.split_host_path(url)
|
|
|
|
|
if url =~ %r{\A[\w+.-]+://(?:[^/@]+@)?([^:/]+)(?::\d+)?/(.+)\z}
|
|
|
|
|
[Regexp.last_match(1), Regexp.last_match(2)]
|
|
|
|
|
elsif url =~ /\A[^@\s]+@([^:]+):(.+)\z/
|
|
|
|
|
[Regexp.last_match(1), Regexp.last_match(2)]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
private_class_method :split_host_path
|
|
|
|
|
end
|
|
|
|
|
end
|