Class: RepoTender::Forge::GitHub

Inherits:
Client
  • Object
show all
Defined in:
lib/repo_tender/forge/github.rb

Overview

‘gh repo list <org> –json …` implementation of Forge::Client.

Per AGENTS.md gotcha, ‘gh` can silently fall back to unauthenticated (60 req/hr). We probe `gh auth status` once (via the engine calling check_authenticated before listing) and surface a clear Failure rather than risking the rate-limit wall.

Constant Summary collapse

LIST_LIMIT =

Default page size for ‘gh repo list`. Matches gh’s own –limit cap; orgs with >1000 repos are out of scope for Slice 1.

1000

Instance Method Summary collapse

Constructor Details

#initialize(shell: Shell) ⇒ GitHub

Returns a new instance of GitHub.



21
22
23
# File 'lib/repo_tender/forge/github.rb', line 21

def initialize(shell: Shell)
  @shell = shell
end

Instance Method Details

#build_argv(org_ref) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/repo_tender/forge/github.rb', line 58

def build_argv(org_ref)
  # G11 fix (Slice 2): `--no-source` is NOT a valid `gh repo list`
  # flag (`gh repo list --help` lists `--archived`, `--no-archived`,
  # `--fork`, `--source`, `--json`, `--limit`, `--topic`,
  # `--language`, `--visibility`, `--jq`, `--template` — no
  # `--no-source`). Fork exclusion is handled authoritatively in
  # `parse_repos` below (the `include_forks` filter), so we no
  # longer emit an advisory CLI flag for it. The existing G6
  # behavioral tests for `include_forks=false` still pass.
  argv = ["gh", "repo", "list", org_ref.name, "--json", "nameWithOwner,defaultBranchRef,isArchived,isFork", "--limit", LIST_LIMIT.to_s]
  argv << "--no-archived" unless org_ref.include_archived
  argv
end

#check_authenticatedObject

Probe ‘gh auth status`. On stderr the unauthenticated case is obvious: “You are not logged into any GitHub hosts.” We treat that exact phrase as Failure; otherwise Success.

Public so the engine can call it once before fanning out org listings. ‘list_org` no longer authenticates per-call.



31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/repo_tender/forge/github.rb', line 31

def check_authenticated
  # `gh auth status` writes a human-friendly summary to stdout
  # and exits 0 when authenticated, 1 when not. We also fail
  # when the binary is missing (status 127 from the shell).
  result = @shell.run("gh", "auth", "status")
  return result if result.failure?

  if result.success.include?("not logged into any GitHub hosts")
    Dry::Monads::Failure({reason: "gh not authenticated; run `gh auth login` first"})
  else
    Dry::Monads::Success(:authenticated)
  end
end

#list_org(org_ref) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/repo_tender/forge/github.rb', line 45

def list_org(org_ref)
  return Dry::Monads::Failure({org: org_ref.name, reason: "missing org name"}) if org_ref.name.nil? || org_ref.name.empty?

  argv = build_argv(org_ref)
  result = @shell.run(*argv)
  return result if result.failure?

  parsed = parse_repos(result.success, org_ref)
  Dry::Monads::Success(parsed)
rescue JSON::ParserError => e
  Dry::Monads::Failure({org: org_ref.name, reason: "invalid JSON from gh", error: e.message})
end