hiiro 0.1.289 → 0.1.290

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37466eb01d7284c838b3ba958f35a41e0f33f4f4fd5c22036ce11f2daa13bfb4
4
- data.tar.gz: 55b421c1b3c124cc265d14c93f7709d0e2c894d4497125884306fbe53fe29762
3
+ metadata.gz: 39db2e632092be3971a6cb08da3a0a4a4ad3accfc42c6978bccee29ebd9c185f
4
+ data.tar.gz: 02e163c3f894838a6e1ef31d96d2b9f3011bf0ff53e50eee71f4f8c4c8ff1fb4
5
5
  SHA512:
6
- metadata.gz: dc41d3e7f2fc019d20336f0890dcff641d545a3bb25a6b83147fc1067b3a139a2548c498b8f9e825cbe7096c2a4d2d77706ed9e21d79b36b26459db54a2ea3f4
7
- data.tar.gz: 403890caf1a18fe7b5c231b1fd12c2e4d07897867c8e46620441923f2860b4e5c0f7ab848105edb4c773a7d2724f5a4be4048e37155ec31bce78ea387f07fc1c
6
+ metadata.gz: 67bdae476921c82c1aaf61195768b1145b235756ba73687e28ea918dfe43ea8d907471d38d1084dfa2caf82921fe594145f9183073480adc8b140a6d6c998723
7
+ data.tar.gz: 9a824284df02e880db1bb13496610b1ae39c2cbdbbae9f09176640ff8bb6e50d3e9c1a56b84491ef6d5b6ff0742db0cb9f84fe5c3c2a67abc58b42d581279c8d
data/CHANGELOG.md CHANGED
@@ -1,9 +1,16 @@
1
1
  ```markdown
2
+ ## v0.1.290 (2026-03-26)
3
+
4
+ ### Fixed
5
+ - `h pr ls`/`h pr update`: revert `statusCheckRollup` contexts limit to 100 and add pagination to retrieve all checks beyond the first 100; GitHub's GraphQL API silently returns null when limit is exceeded, causing all checks to vanish
6
+
2
7
  ## v0.1.289 (2026-03-26)
3
8
 
4
9
  ### Fixed
5
10
  - `h queue run`/`watch`: frontmatter `session_name` now directly controls which tmux session the task launches in; working directory seeded from that session's active pane when no tree is specified
6
11
  - `h queue sadd`: now immediately launches a new tmux window in the target session after adding to queue, consistent with `hadd`/`vadd` behavior (previously just added to pending with no launch)
12
+ - `h pr ls`: revert `statusCheckRollup` contexts limit from 250 back to 100; GitHub's GraphQL API caps connections at 100 — exceeding it silently returns null for the entire field, causing all checks to vanish from the list
13
+ - `h pr update`: paginate beyond the first 100 checks for PRs that hit the limit; show `❓` status for PRs where pagination still couldn't retrieve all checks
7
14
 
8
15
  ## v0.1.288 (2026-03-26)
9
16
 
data/lib/hiiro/git/pr.rb CHANGED
@@ -106,7 +106,8 @@ class Hiiro
106
106
 
107
107
  # Summarizes raw statusCheckRollup contexts into { total, success, pending, failed, frozen }.
108
108
  # frozen = number of failed contexts that are specifically the ISC code freeze check.
109
- def self.summarize_checks(rollup)
109
+ # truncated: true is added when pagination couldn't retrieve all checks.
110
+ def self.summarize_checks(rollup, truncated: false)
110
111
  return nil unless rollup
111
112
 
112
113
  contexts = rollup.is_a?(Array) ? rollup : []
@@ -126,7 +127,9 @@ class Hiiro
126
127
  (FAILED_CONCLUSIONS.include?(c['conclusion']) || %w[FAILURE ERROR].include?(c['state']))
127
128
  end
128
129
 
129
- { 'total' => total, 'success' => success, 'pending' => pending, 'failed' => failed, 'frozen' => frozen }
130
+ result = { 'total' => total, 'success' => success, 'pending' => pending, 'failed' => failed, 'frozen' => frozen }
131
+ result['truncated'] = true if truncated
132
+ result
130
133
  end
131
134
 
132
135
  # Summarizes raw review nodes into { approved, changes_requested, commented, reviewers }.
@@ -262,7 +262,7 @@ class Hiiro
262
262
  pr.state = info['state']
263
263
  pr.title = info['title']
264
264
  pr.check_runs = rollup
265
- pr.checks = Hiiro::Git::Pr.summarize_checks(rollup)
265
+ pr.checks = Hiiro::Git::Pr.summarize_checks(rollup, truncated: info['checksTruncated'])
266
266
  pr.reviews = Hiiro::Git::Pr.summarize_reviews(info['reviews'])
267
267
  pr.review_decision = info['reviewDecision']
268
268
  pr.is_draft = info['isDraft']
@@ -317,6 +317,8 @@ class Hiiro
317
317
  only_frozen ? " ❄️" : " ❌"
318
318
  elsif has_pending
319
319
  "⏳ "
320
+ elsif c['truncated']
321
+ " ❓"
320
322
  else
321
323
  " ✅"
322
324
  end
@@ -494,44 +496,24 @@ class Hiiro
494
496
  def fetch_batch_for_repo(owner, name, pr_numbers)
495
497
  return {} if pr_numbers.empty?
496
498
 
499
+ context_fragment = <<~GRAPHQL.strip
500
+ __typename
501
+ ... on CheckRun { __typename name conclusion status detailsUrl }
502
+ ... on StatusContext { __typename context state targetUrl }
503
+ GRAPHQL
504
+
497
505
  pr_queries = pr_numbers.map.with_index do |num, idx|
498
506
  <<~GRAPHQL.strip
499
507
  pr#{idx}: pullRequest(number: #{num}) {
500
- number
501
- title
502
- url
503
- headRefName
504
- state
505
- isDraft
506
- mergeable
507
- reviewDecision
508
+ number title url headRefName state isDraft mergeable reviewDecision
508
509
  statusCheckRollup {
509
- contexts(last: 250) {
510
- nodes {
511
- ... on CheckRun {
512
- __typename
513
- name
514
- conclusion
515
- status
516
- detailsUrl
517
- }
518
- ... on StatusContext {
519
- __typename
520
- context
521
- state
522
- targetUrl
523
- }
524
- }
525
- }
526
- }
527
- reviews(last: 50) {
528
- nodes {
529
- author {
530
- login
531
- }
532
- state
510
+ contexts(last: 100) {
511
+ totalCount
512
+ pageInfo { hasPreviousPage startCursor }
513
+ nodes { #{context_fragment} }
533
514
  }
534
515
  }
516
+ reviews(last: 50) { nodes { author { login } state } }
535
517
  }
536
518
  GRAPHQL
537
519
  end
@@ -557,18 +539,36 @@ class Hiiro
557
539
  pr_data = repo_data["pr#{idx}"]
558
540
  next unless pr_data
559
541
 
542
+ contexts_data = pr_data.dig('statusCheckRollup', 'contexts')
543
+ nodes = contexts_data&.[]('nodes') || []
544
+ total_count = contexts_data&.[]('totalCount').to_i
545
+ page_info = contexts_data&.[]('pageInfo') || {}
546
+
547
+ # Paginate backwards to collect all checks beyond the first 100
548
+ all_nodes = nodes.dup
549
+ cursor = page_info['startCursor']
550
+ while page_info['hasPreviousPage'] && cursor
551
+ extra_nodes, page_info = fetch_contexts_page(owner, name, num, cursor, context_fragment)
552
+ break unless extra_nodes
553
+ all_nodes = extra_nodes + all_nodes
554
+ cursor = page_info&.[]('startCursor')
555
+ end
556
+
557
+ truncated = total_count > 0 && all_nodes.length < total_count
558
+
560
559
  pr_info_by_key[[num, repo_path]] = {
561
- 'number' => pr_data['number'],
562
- 'title' => pr_data['title'],
563
- 'url' => pr_data['url'],
564
- 'headRefName' => pr_data['headRefName'],
565
- 'state' => pr_data['state'],
566
- 'isDraft' => pr_data['isDraft'],
567
- 'mergeable' => pr_data['mergeable'],
568
- 'reviewDecision' => pr_data['reviewDecision'],
569
- 'statusCheckRollup' => pr_data.dig('statusCheckRollup', 'contexts', 'nodes'),
570
- 'reviews' => pr_data.dig('reviews', 'nodes') || [],
571
- 'repo' => repo_path
560
+ 'number' => pr_data['number'],
561
+ 'title' => pr_data['title'],
562
+ 'url' => pr_data['url'],
563
+ 'headRefName' => pr_data['headRefName'],
564
+ 'state' => pr_data['state'],
565
+ 'isDraft' => pr_data['isDraft'],
566
+ 'mergeable' => pr_data['mergeable'],
567
+ 'reviewDecision' => pr_data['reviewDecision'],
568
+ 'statusCheckRollup'=> all_nodes.any? ? all_nodes : nil,
569
+ 'checksTruncated' => truncated,
570
+ 'reviews' => pr_data.dig('reviews', 'nodes') || [],
571
+ 'repo' => repo_path
572
572
  }
573
573
  end
574
574
 
@@ -577,6 +577,33 @@ class Hiiro
577
577
  {}
578
578
  end
579
579
 
580
+ def fetch_contexts_page(owner, name, pr_number, before_cursor, context_fragment)
581
+ query = <<~GRAPHQL
582
+ query {
583
+ repository(owner: "#{owner}", name: "#{name}") {
584
+ pullRequest(number: #{pr_number}) {
585
+ statusCheckRollup {
586
+ contexts(last: 100, before: "#{before_cursor}") {
587
+ pageInfo { hasPreviousPage startCursor }
588
+ nodes { #{context_fragment} }
589
+ }
590
+ }
591
+ }
592
+ }
593
+ }
594
+ GRAPHQL
595
+
596
+ result = `gh api graphql -f query='#{query.gsub("'", "'\\''")}' 2>/dev/null`
597
+ return [nil, nil] if result.empty?
598
+
599
+ contexts = JSON.parse(result).dig('data', 'repository', 'pullRequest', 'statusCheckRollup', 'contexts')
600
+ return [nil, nil] unless contexts
601
+
602
+ [contexts['nodes'] || [], contexts['pageInfo'] || {}]
603
+ rescue JSON::ParserError, StandardError
604
+ [nil, nil]
605
+ end
606
+
580
607
  def check_run_emoji(conclusion, status)
581
608
  return "⏳" if %w[QUEUED IN_PROGRESS PENDING REQUESTED WAITING].include?(status) && conclusion.nil?
582
609
  case conclusion
data/lib/hiiro/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Hiiro
2
- VERSION = "0.1.289"
2
+ VERSION = "0.1.290"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiiro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.289
4
+ version: 0.1.290
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Toyota