git-markdown 0.1.7 → 0.1.9

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: 7b54256dcd569639e4995d505d50c18635935bf4a397aab6b61ab9d03354cf60
4
- data.tar.gz: da76e2e67d339131b9e0044f2ebd7069ef6dfadbcc27ac0d84fbb1e194792b0a
3
+ metadata.gz: 76a5b1c374e3b1570dbc81b878c599fbe4948bb82f34ac3e7b83b838fba9f8fa
4
+ data.tar.gz: e59928ca3d2c0e06662c1c3bd5de7a9e6a8dd08fe185107902442a9dc96644aa
5
5
  SHA512:
6
- metadata.gz: 10de61bf0523a66e46aab43b637d7132d76c4bdbb878ce94c900c4a319d5c0841d2329166b48922134ab42f10f308d4e689efc2bdeb25da9ace585b836231113
7
- data.tar.gz: 65ca8d4ec9d25fbd51a7442827551beaf50d79974b2f9d07327d0860d75ac9fa7a1ed093ac3eb0aa178aaf2ecb1541699b5c72c95c6b4533f8eae34b6f14d981
6
+ metadata.gz: 06eca733ed11a7e397f050a3e12080c0354e12c4fe1f760dec9e0237a919e5eaa4d5b65af451356ffceed818c095d0829908f5feb0df0b7eac2b5408e34bb5ff
7
+ data.tar.gz: 0545bb27e46d36a396c5963fbefc4f37a9c00b96ae275872cb0c959e9b3724aa994dc0078c58c900d0b8594f0ba035d4749d876d48d6cb2ac7db286dc62327b2
data/AGENT.md ADDED
@@ -0,0 +1,47 @@
1
+ # Agent Guide
2
+
3
+ Repository-specific rules for code-generation agents working on `git-markdown`.
4
+
5
+ ## Core workflow
6
+
7
+ - Prefer surgical edits. Do not reformat unrelated code or reshuffle files.
8
+ - Read the actual call sites and CLI flows before changing behavior.
9
+ - Preserve the public CLI and generated Markdown shape unless the task explicitly requires a change.
10
+ - Fix root causes, not symptoms.
11
+ - Keep one canonical owner per behavior:
12
+ - remote parsing in `Git::Markdown::RemoteParser`
13
+ - auth/config in `Git::Markdown::Configuration` and `Git::Markdown::Credentials`
14
+ - provider fetching in `Git::Markdown::Providers::*`
15
+ - HTTP transport/response handling in `Git::Markdown::Api::*`
16
+ - output rendering in `Git::Markdown::Markdown::Generator`
17
+
18
+ ## Naming and code quality
19
+
20
+ - Use one canonical term per concept across code, config, and docs.
21
+ - Do not add parallel wrappers or aliases for the same concept.
22
+ - Use clear names that describe the domain object or action; avoid vague names like `Manager`, `Helper`, or `Handler`.
23
+ - Keep classes small and intention-revealing. If logic starts spanning transport, parsing, and rendering concerns, split by responsibility rather than adding conditionals.
24
+ - Fail fast on unexpected states. Prefer explicit errors over silent fallbacks.
25
+ - When tests are hard to write, simplify the production design first instead of adding test-only indirection.
26
+
27
+ ## Testing and boundaries
28
+
29
+ - Framework: Minitest.
30
+ - Keep WebMock enabled. Do not allow live HTTP in tests.
31
+ - Use VCR for outbound GitHub API interactions when fixtures are needed.
32
+ - Add or update minimal tests when behavior changes, especially for CLI output, parsing, and provider interactions.
33
+ - Use `standardrb` for Ruby style consistency.
34
+ - Run `bundle exec rake` before finishing.
35
+
36
+ ## Git commits and release
37
+
38
+ - Conventional Commits are required and enforced by `commitlint`.
39
+ - Allowed commit types for normal work: `feat`, `fix`, `refactor`, `chore`, `test`, `docs`.
40
+ - Subject line: imperative, <= 80 chars, no trailing period.
41
+ - Add a body for non-trivial changes explaining why and how.
42
+ - Install hooks once per clone: `bundle exec lefthook install`
43
+ - Release flow:
44
+ - `bundle exec rake 'release:prepare[patch]'`
45
+ - changelog is generated by `git-cliff`
46
+ - publishing happens only in GitHub Actions
47
+ - this gem publishes only to RubyGems
data/CHANGELOG.md CHANGED
@@ -5,9 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [0.1.7] - 2026-02-08
8
+ ## [0.1.9] - 2026-04-21
9
9
 
10
10
  ### <!-- 1 -->🐛 Bug Fixes
11
- - read version from GitMarkdown::VERSION constant
11
+ - publish built gem in release workflow
12
+
13
+
14
+ ### <!-- 3 -->📚 Documentation
15
+ - update gemspec and readme
16
+
17
+
18
+ ### <!-- 7 -->⚙️ Miscellaneous Tasks
19
+ - standardize gem release workflow and repo conventions
20
+ - stop using github variables
12
21
 
13
22
 
data/Gemfile CHANGED
@@ -5,8 +5,6 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in git-markdown.gemspec
6
6
  gemspec
7
7
 
8
- gem "gem-release", "~> 2.2"
9
-
10
8
  group :development do
11
9
  gem "commitlint", require: false
12
10
  gem "lefthook", require: false
data/README.md CHANGED
@@ -130,7 +130,7 @@ Note: `Gemfile.lock` is intentionally not tracked to avoid conflicts across Ruby
130
130
 
131
131
  ### Git hooks
132
132
 
133
- We use [lefthook](https://lefthook.dev/) with the Ruby [commitlint](https://github.com/arandilopez/commitlint) gem to enforce Conventional Commits on every commit. CI also validates commit messages on pull requests and pushes to main/master.
133
+ We use [lefthook](https://lefthook.dev/) with the Ruby [commitlint](https://github.com/arandilopez/commitlint) gem to enforce Conventional Commits on every commit. We also use [Standard Ruby](https://standardrb.com/) to keep code style consistent. CI validates commit messages, Standard Ruby, tests, and git-cliff changelog generation on pull requests and pushes to main/master.
134
134
 
135
135
  Run the hook installer once per clone:
136
136
 
@@ -146,27 +146,29 @@ rake install
146
146
 
147
147
  ## Release
148
148
 
149
- Releases are triggered by pushed tags and use `CHANGELOG.md` for GitHub release notes.
149
+ Releases are tag-driven and published by GitHub Actions to RubyGems. Local release commands never publish directly.
150
150
 
151
- If you want changelog automation, install `git-cliff` (<https://github.com/orhun/git-cliff>) locally and use it to update `CHANGELOG.md`.
151
+ Install [git-cliff](https://git-cliff.org/) locally before preparing a release. The release task regenerates `CHANGELOG.md` from Conventional Commits.
152
152
 
153
- The release workflow expects a `## [X.Y.Z]` entry in `CHANGELOG.md` that matches the tag. Note: `release:prep` enforces a clean working tree and must run on the `main` or `master` branch; it will skip if the changelog has no changes.
153
+ Before preparing a release, make sure you are on `main` or `master` with a clean worktree.
154
154
 
155
- Before bumping, install dependencies:
155
+ Then run one of:
156
156
 
157
157
  ```bash
158
- bundle install
158
+ bundle exec rake 'release:prepare[patch]'
159
+ bundle exec rake 'release:prepare[minor]'
160
+ bundle exec rake 'release:prepare[major]'
161
+ bundle exec rake 'release:prepare[0.1.0]'
159
162
  ```
160
163
 
161
- Then run:
164
+ The task will:
162
165
 
163
- ```bash
164
- # 1) Bump the version (commit created)
165
- bundle exec gem bump -v X.Y.Z
166
+ 1. Regenerate `CHANGELOG.md` with `git-cliff`.
167
+ 1. Update `lib/git/markdown/version.rb`.
168
+ 1. Commit the release changes.
169
+ 1. Create and push the `vX.Y.Z` tag.
166
170
 
167
- # 2) Prepare release (changelog + tag + push)
168
- bundle exec rake release:prep
169
- ```
171
+ The `Release` workflow then runs tests, publishes the gem to RubyGems, and creates the GitHub release from the changelog entry.
170
172
 
171
173
  ## Contributing
172
174
 
@@ -199,7 +201,7 @@ MIT License, see [LICENSE.txt](LICENSE.txt)
199
201
 
200
202
  ## About
201
203
 
202
- Made by the team at [Ethos Link](https://www.ethos-link.com) — practical software for growing businesses. We build tools for hospitality and retail teams who don’t have time for complicated setups: plain-language insights, fast onboarding, and real human support so you can get clear insights, take action, and move on.
204
+ Made by the team at [Ethos Link](https://www.ethos-link.com) — practical software for growing businesses. We build tools for hospitality operators who need clear workflows, fast onboarding, and real human support.
203
205
 
204
- We also build [Reviato](https://www.reviato.com), “More stars. Less hassle.”.
205
- Reviato helps restaurants, hotels, clinics, vets and other local businesses collect and analyse customer reviews, highlights recurring themes, and turns feedback into actionable next steps.
206
+ We also build [Reviato](https://www.reviato.com), “Capture. Interpret. Act.”.
207
+ Turn guest feedback into clear next steps for your team. Collect private appraisals, spot patterns across reviews, and act before small issues turn into public ones.
data/Rakefile CHANGED
@@ -1,89 +1,99 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Note: Releases are handled automatically by GitHub Actions when you push a tag (e.g., v0.2.0)
4
- # See .github/workflows/release.yml for details
5
3
  require "bundler/gem_tasks"
6
4
  require "rake/testtask"
7
5
  require "standard/rake"
8
6
  require_relative "lib/git/markdown/version"
9
7
 
8
+ VERSION_PATH = File.expand_path("lib/git/markdown/version.rb", __dir__)
9
+ VALID_RELEASE_TARGETS = %w[major minor patch].freeze
10
+
10
11
  Rake::TestTask.new(:test) do |t|
11
12
  t.libs << "test"
12
13
  t.libs << "lib"
13
14
  t.test_files = FileList["test/**/*_test.rb"]
14
15
  end
15
16
 
16
- task default: %i[test standard]
17
+ def current_branch
18
+ `git branch --show-current`.strip
19
+ end
17
20
 
18
- namespace :release do
19
- desc "Full release: update changelog, bump version, commit, tag, and push"
20
- task :bump, [:level] do |_t, args|
21
- level = args[:level] || "patch"
22
- valid_levels = %w[major minor patch pre]
21
+ def clean_worktree?
22
+ system("git diff --quiet") && system("git diff --cached --quiet")
23
+ end
24
+
25
+ def release_version(target)
26
+ target = target.to_s.strip
27
+ raise ArgumentError, "Provide patch, minor, major, or an explicit X.Y.Z version." if target.empty?
28
+
29
+ return target if target.match?(/\A\d+\.\d+\.\d+\z/)
30
+
31
+ unless VALID_RELEASE_TARGETS.include?(target)
32
+ raise ArgumentError, "Invalid release target #{target.inspect}. Use #{VALID_RELEASE_TARGETS.join(", ")} or X.Y.Z."
33
+ end
34
+
35
+ major, minor, patch = GitMarkdown::VERSION.split(".").map(&:to_i)
36
+
37
+ case target
38
+ when "major"
39
+ "#{major + 1}.0.0"
40
+ when "minor"
41
+ "#{major}.#{minor + 1}.0"
42
+ when "patch"
43
+ "#{major}.#{minor}.#{patch + 1}"
44
+ end
45
+ end
46
+
47
+ def update_version_file(version)
48
+ File.write(
49
+ VERSION_PATH,
50
+ <<~RUBY
51
+ # frozen_string_literal: true
52
+
53
+ module GitMarkdown
54
+ VERSION = "#{version}"
55
+ end
56
+ RUBY
57
+ )
58
+ end
23
59
 
24
- unless valid_levels.include?(level)
25
- abort "Invalid level: #{level}. Use: #{valid_levels.join(", ")}"
26
- end
60
+ def update_changelog(version)
61
+ success = system("git-cliff", "-c", "cliff.toml", "--unreleased", "--tag", "v#{version}", "-o", "CHANGELOG.md")
62
+ raise "git-cliff failed. Install git-cliff and make sure cliff.toml is valid." unless success
63
+ raise "git-cliff did not update CHANGELOG.md. Ensure there are Conventional Commits since the last tag." if system("git", "diff", "--quiet", "--", "CHANGELOG.md")
64
+ end
65
+
66
+ if Rake::Task.task_defined?("release")
67
+ Rake::Task["release"].clear
68
+ end
27
69
 
28
- branch = `git rev-parse --abbrev-ref HEAD`.strip
29
- unless ["main", "master"].include?(branch)
30
- abort "Release must run on main or master. Current: #{branch}."
31
- end
70
+ desc "Publishing is handled by GitHub Actions. Use release:prepare[...] instead."
71
+ task :release do
72
+ abort "Use `bundle exec rake 'release:prepare[patch]'` (or minor/major/X.Y.Z). Publishing runs in GitHub Actions after the tag is pushed."
73
+ end
32
74
 
33
- unless system("git diff --quiet") && system("git diff --cached --quiet")
34
- abort "Release requires a clean working tree."
35
- end
75
+ namespace :release do
76
+ desc "Prepare a release: update CHANGELOG/version, commit, tag, and push. Accepts patch, minor, major, or X.Y.Z."
77
+ task :prepare, [:target] do |_task, args|
78
+ branch = current_branch
79
+ abort "Release must run on main or master. Current branch: #{branch.inspect}." unless %w[main master].include?(branch)
80
+ abort "Release requires a clean working tree." unless clean_worktree?
36
81
 
82
+ version = release_version(args[:target])
37
83
  current = GitMarkdown::VERSION
38
- parts = current.split(".").map(&:to_i)
39
-
40
- next_version = case level
41
- when "major"
42
- "#{parts[0] + 1}.0.0"
43
- when "minor"
44
- "#{parts[0]}.#{parts[1] + 1}.0"
45
- when "patch"
46
- "#{parts[0]}.#{parts[1]}.#{parts[2] + 1}"
47
- when "pre"
48
- "#{parts[0]}.#{parts[1]}.#{parts[2]}.pre.1"
49
- end
50
-
51
- puts "=== Step 1: Updating CHANGELOG.md for v#{next_version} ==="
52
- sh "git cliff -c cliff.toml --unreleased --tag v#{next_version} -o CHANGELOG.md"
53
-
54
- if system("git diff --quiet -- CHANGELOG.md")
55
- puts "Warning: No changelog changes detected"
56
- else
57
- puts "✓ Changelog updated"
58
- end
59
-
60
- puts "\n=== Step 2: Bumping version to #{next_version} ==="
61
-
62
- File.write(
63
- "lib/git/markdown/version.rb",
64
- <<~RUBY
65
- # frozen_string_literal: true
66
-
67
- module GitMarkdown
68
- VERSION = "#{next_version}"
69
- end
70
- RUBY
71
- )
72
-
73
- puts "✓ Version updated in lib/git/markdown/version.rb"
74
-
75
- puts "\n=== Step 3: Committing changes ==="
76
- sh "git add CHANGELOG.md lib/git/markdown/version.rb"
77
- sh "git commit -m \"chore(release): bump version to #{next_version}\""
78
- puts "✓ Changes committed"
84
+ abort "Release version #{version} is older than current version #{current}." if Gem::Version.new(version) < Gem::Version.new(current)
79
85
 
80
- puts "\n=== Step 4: Creating and pushing tag ==="
81
- sh "git tag -a v#{next_version} -m \"Release v#{next_version}\""
82
- sh "git push origin master"
83
- sh "git push origin v#{next_version}"
84
- puts "✓ Tag v#{next_version} created and pushed"
86
+ update_changelog(version)
87
+ update_version_file(version)
85
88
 
86
- puts "\n✅ Release v#{next_version} prepared successfully!"
87
- puts "GitHub Actions will now build and publish the release."
89
+ sh "git add CHANGELOG.md lib/git/markdown/version.rb"
90
+ sh %(git commit -m "chore(release): prepare v#{version}")
91
+ sh %(git tag -a v#{version} -m "Release v#{version}")
92
+ sh "git push origin #{branch}"
93
+ sh "git push origin v#{version}"
94
+ rescue ArgumentError, RuntimeError => e
95
+ abort e.message
88
96
  end
89
97
  end
98
+
99
+ task default: %i[test standard]
data/git-markdown.gemspec CHANGED
@@ -6,6 +6,7 @@ Gem::Specification.new do |spec|
6
6
  spec.name = "git-markdown"
7
7
  spec.version = GitMarkdown::VERSION
8
8
  spec.authors = ["Paulo Fidalgo", "Ethos Link"]
9
+ spec.email = ["devel@ethos-link.com"]
9
10
 
10
11
  spec.summary = "Convert GitHub PRs to Markdown for local AI code review"
11
12
  spec.description = "A CLI tool that fetches GitHub pull requests and converts them to Markdown format, perfect for local AI assistants like opencode and codex."
@@ -23,6 +24,8 @@ Gem::Specification.new do |spec|
23
24
  "changelog_uri" => "#{repo}/blob/#{branch}/CHANGELOG.md",
24
25
  "documentation_uri" => "#{repo}/blob/#{branch}/README.md",
25
26
  "funding_uri" => "https://www.reviato.com/",
27
+ "github_repo" => "ssh://github.com/ethos-link/git-markdown",
28
+ "allowed_push_host" => "https://rubygems.org",
26
29
  "rubygems_mfa_required" => "true"
27
30
  }
28
31
 
@@ -17,6 +17,17 @@ module GitMarkdown
17
17
  Response.new(response)
18
18
  end
19
19
 
20
+ def post(path, body = {})
21
+ uri = build_uri(path, {})
22
+ request = Net::HTTP::Post.new(uri)
23
+ set_headers(request)
24
+ request["Content-Type"] = "application/json"
25
+ request.body = JSON.generate(body)
26
+
27
+ response = http_request(uri, request)
28
+ Response.new(response)
29
+ end
30
+
20
31
  private
21
32
 
22
33
  def build_uri(path, params)
@@ -7,13 +7,14 @@ module GitMarkdown
7
7
  XDG_CONFIG_HOME = ENV.fetch("XDG_CONFIG_HOME", File.expand_path("~/.config"))
8
8
  DEFAULT_PROVIDER = :github
9
9
 
10
- attr_accessor :token, :provider, :api_url, :output_dir, :default_status
10
+ attr_accessor :token, :provider, :api_url, :graphql_url, :output_dir, :default_status
11
11
 
12
12
  def initialize
13
13
  @provider = DEFAULT_PROVIDER
14
14
  @output_dir = Dir.pwd
15
15
  @default_status = :unresolved
16
16
  @api_url = nil
17
+ @graphql_url = nil
17
18
  end
18
19
 
19
20
  def self.load
@@ -24,6 +25,7 @@ module GitMarkdown
24
25
  load_from_file if config_file_exist?
25
26
  resolve_credentials
26
27
  resolve_api_url if api_url.nil?
28
+ resolve_graphql_url if graphql_url.nil?
27
29
  self
28
30
  end
29
31
 
@@ -67,6 +69,7 @@ module GitMarkdown
67
69
  )
68
70
  @provider = config[:provider] if config[:provider]
69
71
  @api_url = config[:api_url] if config[:api_url]
72
+ @graphql_url = config[:graphql_url] if config[:graphql_url]
70
73
  @output_dir = config[:output_dir] if config[:output_dir]
71
74
  @default_status = config[:default_status].to_sym if config[:default_status]
72
75
  end
@@ -81,10 +84,17 @@ module GitMarkdown
81
84
  end
82
85
  end
83
86
 
87
+ def resolve_graphql_url
88
+ @graphql_url = ENV.fetch("GITHUB_GRAPHQL_URL") do
89
+ (@provider == :github) ? "https://api.github.com/graphql" : nil
90
+ end
91
+ end
92
+
84
93
  def config_to_yaml
85
94
  {
86
95
  provider: @provider,
87
96
  api_url: @api_url,
97
+ graphql_url: @graphql_url,
88
98
  output_dir: @output_dir,
89
99
  default_status: @default_status
90
100
  }.to_yaml
@@ -50,9 +50,9 @@ module GitMarkdown
50
50
  def include_comment?(comment)
51
51
  case @status_filter
52
52
  when :unresolved
53
- !comment.body.include?("[resolved]") && !comment.body.include?("[done]")
53
+ !comment.resolved? && !comment.body.include?("[resolved]") && !comment.body.include?("[done]")
54
54
  when :resolved
55
- comment.body.include?("[resolved]") || comment.body.include?("[done]")
55
+ comment.resolved? || comment.body.include?("[resolved]") || comment.body.include?("[done]")
56
56
  else
57
57
  true
58
58
  end
@@ -4,6 +4,7 @@ module GitMarkdown
4
4
  module Models
5
5
  class Comment
6
6
  attr_reader :id, :body, :author, :path, :line, :html_url, :created_at, :updated_at, :in_reply_to_id
7
+ attr_accessor :resolved
7
8
 
8
9
  def initialize(attrs = {})
9
10
  @id = attrs[:id]
@@ -15,6 +16,7 @@ module GitMarkdown
15
16
  @created_at = attrs[:created_at]
16
17
  @updated_at = attrs[:updated_at]
17
18
  @in_reply_to_id = attrs[:in_reply_to_id]
19
+ @resolved = attrs.fetch(:resolved, false)
18
20
  end
19
21
 
20
22
  def self.from_api(data)
@@ -38,6 +40,10 @@ module GitMarkdown
38
40
  def reply?
39
41
  !@in_reply_to_id.nil?
40
42
  end
43
+
44
+ def resolved?
45
+ @resolved == true
46
+ end
41
47
  end
42
48
  end
43
49
  end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GitMarkdown
4
+ module Providers
5
+ class GitHub
6
+ class Graphql
7
+ RESOLVED_STATE_QUERY = <<~GRAPHQL
8
+ query($owner: String!, $repo: String!, $number: Int!, $threadsAfter: String, $commentsAfter: String) {
9
+ repository(owner: $owner, name: $repo) {
10
+ pullRequest(number: $number) {
11
+ reviewThreads(first: 100, after: $threadsAfter) {
12
+ pageInfo {
13
+ hasNextPage
14
+ endCursor
15
+ }
16
+ nodes {
17
+ isResolved
18
+ comments(first: 100, after: $commentsAfter) {
19
+ pageInfo {
20
+ hasNextPage
21
+ endCursor
22
+ }
23
+ nodes {
24
+ databaseId
25
+ body
26
+ path
27
+ line
28
+ createdAt
29
+ updatedAt
30
+ author {
31
+ login
32
+ }
33
+ replyTo {
34
+ databaseId
35
+ }
36
+ url
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ GRAPHQL
45
+
46
+ def initialize(config)
47
+ @config = config
48
+ end
49
+
50
+ def fetch_resolved_states(owner, repo, number)
51
+ resolved_ids = Set.new
52
+ threads_after = nil
53
+
54
+ loop do
55
+ response = client.post("", {
56
+ query: RESOLVED_STATE_QUERY,
57
+ variables: {owner: owner, repo: repo, number: number,
58
+ threadsAfter: threads_after}
59
+ })
60
+
61
+ raise ApiError, "GraphQL request failed: #{response.error_message}" unless response.success?
62
+
63
+ data = response.data
64
+ threads_data = data.dig("data", "repository", "pullRequest", "reviewThreads")
65
+ break unless threads_data
66
+
67
+ threads_data["nodes"].each do |thread|
68
+ next unless thread["isResolved"]
69
+
70
+ thread["comments"]["nodes"].each do |comment|
71
+ resolved_ids.add(comment["databaseId"]) if comment["databaseId"]
72
+ end
73
+ end
74
+
75
+ threads_page = threads_data["pageInfo"]
76
+ break unless threads_page["hasNextPage"]
77
+
78
+ threads_after = threads_page["endCursor"]
79
+ end
80
+
81
+ resolved_ids
82
+ end
83
+
84
+ private
85
+
86
+ def client
87
+ @client ||= Api::Client.new(
88
+ base_url: @config.graphql_url,
89
+ token: @config.token
90
+ )
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -21,23 +21,36 @@ module GitMarkdown
21
21
  end
22
22
 
23
23
  def fetch_reviews(owner, repo, number)
24
+ resolved_ids = fetch_resolved_comment_ids(owner, repo, number)
25
+
24
26
  path = "/repos/#{owner}/#{repo}/pulls/#{number}/reviews"
25
27
  reviews = fetch_all_pages(path)
26
28
 
29
+ all_pr_comments = fetch_all_pr_comments(owner, repo, number)
30
+
27
31
  reviews.map do |review_data|
28
32
  review = Models::Review.from_api(review_data)
29
- review.comments = fetch_review_comments(owner, repo, review.id)
33
+ review.comments = all_pr_comments
34
+ .select { |c| c["pull_request_review_id"] == review.id }
35
+ .map do |data|
36
+ comment = Models::Comment.from_api(data)
37
+ comment.resolved = resolved_ids.include?(comment.id)
38
+ comment
39
+ end
30
40
  review
31
41
  end
32
42
  end
33
43
 
34
- def fetch_review_comments(owner, repo, review_id)
35
- path = "/repos/#{owner}/#{repo}/pulls/comments"
36
- all_comments = fetch_all_pages(path)
44
+ def fetch_review_comments(owner, repo, review_id, resolved_ids = Set.new)
45
+ all_pr_comments = fetch_all_pr_comments(owner, repo)
37
46
 
38
- all_comments
47
+ all_pr_comments
39
48
  .select { |c| c["pull_request_review_id"] == review_id }
40
- .map { |data| Models::Comment.from_api(data) }
49
+ .map do |data|
50
+ comment = Models::Comment.from_api(data)
51
+ comment.resolved = resolved_ids.include?(comment.id)
52
+ comment
53
+ end
41
54
  end
42
55
 
43
56
  private
@@ -49,6 +62,22 @@ module GitMarkdown
49
62
  )
50
63
  end
51
64
 
65
+ def graphql_client
66
+ @graphql_client ||= Graphql.new(@config)
67
+ end
68
+
69
+ def fetch_resolved_comment_ids(owner, repo, number)
70
+ graphql_client.fetch_resolved_states(owner, repo, number)
71
+ rescue ApiError
72
+ Set.new
73
+ end
74
+
75
+ def fetch_all_pr_comments(owner, repo, _number = nil)
76
+ @all_pr_comments ||= {}
77
+ key = "#{owner}/#{repo}"
78
+ @all_pr_comments[key] ||= fetch_all_pages("/repos/#{owner}/#{repo}/pulls/comments")
79
+ end
80
+
52
81
  def fetch_all_pages(path, params = {})
53
82
  results = []
54
83
  page = 1
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GitMarkdown
4
- VERSION = "0.1.7"
4
+ VERSION = "0.1.9"
5
5
  end
data/lib/git_markdown.rb CHANGED
@@ -15,6 +15,7 @@ require_relative "git/markdown/credentials"
15
15
  require_relative "git/markdown/remote_parser"
16
16
  require_relative "git/markdown/providers/base"
17
17
  require_relative "git/markdown/providers/github"
18
+ require_relative "git/markdown/providers/github/graphql"
18
19
  require_relative "git/markdown/api/client"
19
20
  require_relative "git/markdown/api/response"
20
21
  require_relative "git/markdown/models/pull_request"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-markdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paulo Fidalgo
@@ -96,11 +96,14 @@ dependencies:
96
96
  version: '3.0'
97
97
  description: A CLI tool that fetches GitHub pull requests and converts them to Markdown
98
98
  format, perfect for local AI assistants like opencode and codex.
99
+ email:
100
+ - devel@ethos-link.com
99
101
  executables:
100
102
  - git-markdown
101
103
  extensions: []
102
104
  extra_rdoc_files: []
103
105
  files:
106
+ - AGENT.md
104
107
  - AGENTS.md
105
108
  - CHANGELOG.md
106
109
  - Gemfile
@@ -123,6 +126,7 @@ files:
123
126
  - lib/git/markdown/models/review.rb
124
127
  - lib/git/markdown/providers/base.rb
125
128
  - lib/git/markdown/providers/github.rb
129
+ - lib/git/markdown/providers/github/graphql.rb
126
130
  - lib/git/markdown/remote_parser.rb
127
131
  - lib/git/markdown/version.rb
128
132
  - lib/git_markdown.rb
@@ -136,6 +140,8 @@ metadata:
136
140
  changelog_uri: https://github.com/ethos-link/git-markdown/blob/master/CHANGELOG.md
137
141
  documentation_uri: https://github.com/ethos-link/git-markdown/blob/master/README.md
138
142
  funding_uri: https://www.reviato.com/
143
+ github_repo: ssh://github.com/ethos-link/git-markdown
144
+ allowed_push_host: https://rubygems.org
139
145
  rubygems_mfa_required: 'true'
140
146
  rdoc_options: []
141
147
  require_paths:
@@ -151,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
157
  - !ruby/object:Gem::Version
152
158
  version: '0'
153
159
  requirements: []
154
- rubygems_version: 4.0.3
160
+ rubygems_version: 4.0.6
155
161
  specification_version: 4
156
162
  summary: Convert GitHub PRs to Markdown for local AI code review
157
163
  test_files: []