marlens-github-to-jira-comment 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3d2671f36558d94fbc4e03f4b9fb6d94f406cdaf5cdf0d450ccf97e921446fc9
4
+ data.tar.gz: dab9a7f4e03050178663e4471ed8646648b477d4a16b3800318492f1906e358b
5
+ SHA512:
6
+ metadata.gz: d3420e1f18718e6a3024cca6019ba055754940473e9890740b417fb3b8003c980824051e06b9f06c72761cd7ef156276be77245969424c4515f0ea5fd5ebc515
7
+ data.tar.gz: 0cac0986612cb0f105d57d221e102474c595fbab3e743f937377647f01d957bd0970bfa39241cd00a41c2c18882964ea3bf953ae4801483a9bd3e4b2a1a3efeb
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marlen Brunner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # GitHub to Jira Comment
2
+
3
+ Small Ruby CLI/gem for copying a GitHub issue or pull request body into a Jira issue comment with rich Jira formatting.
4
+
5
+ ## Required contract
6
+
7
+ Both source and destination are URLs, not shorthand tags:
8
+
9
+ ```bash
10
+ github-to-jira-comment \
11
+ --github-url https://github.com/icefoganalytics/wrap/pull/405 \
12
+ --jira-url https://yg-hpw.atlassian.net/browse/WRAPX-388
13
+ ```
14
+
15
+ Credentials come from environment variables. `JIRA_BASE_URL` is optional; the CLI derives it from `--jira-url` unless you override it.
16
+
17
+ ```bash
18
+ GITHUB_TOKEN=...
19
+ JIRA_EMAIL=...
20
+ JIRA_API_TOKEN=...
21
+ ```
22
+
23
+ ## Install
24
+
25
+ ```ruby
26
+ gem "marlens-github-to-jira-comment", "~> 0.1"
27
+ ```
28
+
29
+ ## CLI
30
+
31
+ ```bash
32
+ github-to-jira-comment \
33
+ --github-url https://github.com/icefoganalytics/wrap/pull/405 \
34
+ --jira-url https://yg-hpw.atlassian.net/browse/WRAPX-388
35
+ ```
36
+
37
+ ## Release cycle
38
+
39
+ 1. Work from an issue branch and open a draft PR linked to the issue.
40
+ 2. Run `bundle exec rspec`, `bin/github-to-jira-comment --help`, and `gem build marlens-github-to-jira-comment.gemspec`.
41
+ 3. Delete the generated `.gem` file after the build check.
42
+ 4. Mark the PR ready, merge it to `main`, then update local `main`.
43
+ 5. Build the release artifact from `main` with `gem build marlens-github-to-jira-comment.gemspec`.
44
+ 6. Publish with `gem push marlens-github-to-jira-comment-<version>.gem`.
45
+ 7. Tag the release as `v<version>` and create the GitHub release.
46
+ 8. Verify RubyGems lists the version with `gem list --remote marlens-github-to-jira-comment --exact --all`.
47
+ 9. Install the published gem in a temporary `GEM_HOME` and smoke-check `github-to-jira-comment --help`.
48
+ 10. Delete the local `.gem` artifact after verification.
49
+
50
+ ## MVP scope
51
+
52
+ 1. Accept a full GitHub pull request URL or GitHub issue URL.
53
+ 2. Accept a full Jira issue URL.
54
+ 3. Fetch the GitHub title/body through the GitHub API.
55
+ 4. Convert/post the GitHub body to Jira using `marlens-jira-api`.
56
+ 5. Resolve real GitHub `user-attachments` images while preserving normal links and code blocks.
57
+ 6. Fail on image-upload degradation by using strict image handling.
58
+ 7. Return or print the created Jira comment ID.
59
+
60
+ ## Proved live example
61
+
62
+ - GitHub source: https://github.com/icefoganalytics/wrap/pull/405
63
+ - Jira destination: https://yg-hpw.atlassian.net/browse/WRAPX-388
64
+ - Existing script-created Jira comment: `69213`
65
+ - Created at: `2026-07-09T11:42:26.501-0700`
66
+ - Verified markers:
67
+ - `Fixes https://yg-hpw.atlassian.net/browse/WRAPX-388` rendered as text + Jira link mark.
68
+ - `# Context` rendered as an ADF heading.
69
+ - numbered Implementation/Testing lists rendered as ordered lists.
70
+ - testing commands rendered as code marks.
71
+
72
+ See `docs/HANDOFF.md` for implementation notes and source artifacts.
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/marlens/github_to_jira_comment"
5
+
6
+ exit(Marlens::GithubToJiraComment::CLI.run(ARGV))
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+ require "marlens/jira_api"
5
+
6
+ module Marlens
7
+ module GithubToJiraComment
8
+ class CLI
9
+ def self.run(argv = ARGV, env: ENV, out: $stdout, err: $stderr, github_client_factory: nil, jira_client_factory: nil)
10
+ new(env:, out:, err:, github_client_factory:, jira_client_factory:).call(argv)
11
+ end
12
+
13
+ def initialize(env: ENV, out: $stdout, err: $stderr, github_client_factory: nil, jira_client_factory: nil, markdown_resolver_factory: nil, comment_poster_factory: nil)
14
+ @env = env
15
+ @out = out
16
+ @err = err
17
+ @github_client_factory = github_client_factory
18
+ @jira_client_factory = jira_client_factory
19
+ @markdown_resolver_factory = markdown_resolver_factory
20
+ @comment_poster_factory = comment_poster_factory
21
+ end
22
+
23
+ def call(argv)
24
+ options = parse_options(argv.dup)
25
+ missing = %i[github_url jira_url].select { |key| options[key].to_s.empty? }
26
+ return fail_with("Missing required option(s): #{option_names(missing)}") unless missing.empty?
27
+
28
+ source = github_client.fetch(options.fetch(:github_url))
29
+ resolved = resolve_markdown(source.body, github_url: options.fetch(:github_url))
30
+ result = post_comment(options.fetch(:jira_url), resolved)
31
+
32
+ @out.puts(result.fetch("id") { result.fetch(:id) })
33
+ 0
34
+ rescue ArgumentError, KeyError, OptionParser::ParseError, RuntimeError => error
35
+ fail_with(error.message)
36
+ end
37
+
38
+ private
39
+
40
+ ResolvedMarkdown = Struct.new(:markdown, :allowed_image_hosts, keyword_init: true)
41
+
42
+ def parse_options(argv)
43
+ options = {}
44
+ OptionParser.new do |parser|
45
+ parser.banner = "Usage: github-to-jira-comment --github-url URL --jira-url URL"
46
+ parser.on("--github-url URL", "GitHub pull request or issue URL") { |value| options[:github_url] = value }
47
+ parser.on("--jira-url URL", "Jira browse URL") { |value| options[:jira_url] = value }
48
+ end.parse!(argv)
49
+ options
50
+ end
51
+
52
+ def resolve_markdown(markdown, github_url:)
53
+ resolver = markdown_resolver
54
+ result = if resolver.respond_to?(:resolve_with_metadata)
55
+ resolver.resolve_with_metadata(markdown, context: GithubUrl.parse(github_url).context)
56
+ else
57
+ resolver.resolve(markdown)
58
+ end
59
+ result.respond_to?(:markdown) ? result : ResolvedMarkdown.new(markdown: result, allowed_image_hosts: CommentPoster::DEFAULT_IMAGE_HOSTS)
60
+ end
61
+
62
+ def post_comment(jira_url, resolved)
63
+ poster = comment_poster(jira_url)
64
+ options = {
65
+ jira_url:,
66
+ markdown: resolved.markdown,
67
+ allowed_image_hosts: resolved.allowed_image_hosts,
68
+ }
69
+ poster.post(**options)
70
+ end
71
+
72
+ def github_client
73
+ @github_client ||= @github_client_factory&.call || GithubClient.new(token: @env.fetch("GITHUB_TOKEN"))
74
+ end
75
+
76
+ def markdown_resolver
77
+ @markdown_resolver ||= @markdown_resolver_factory&.call || GithubMarkdownResolver.new(github_client: github_client)
78
+ end
79
+
80
+ def comment_poster(jira_url)
81
+ @comment_poster ||= @comment_poster_factory&.call || CommentPoster.new(jira_client: jira_client(jira_url))
82
+ end
83
+
84
+ def jira_client(jira_url)
85
+ jira_issue = JiraUrl.parse(jira_url)
86
+ return @jira_client_factory.call(env: @env, base_url: @env["JIRA_BASE_URL"] || jira_issue.base_url) if @jira_client_factory
87
+
88
+ Marlens::JiraApi::Client.new(
89
+ base_url: @env["JIRA_BASE_URL"] || jira_issue.base_url,
90
+ email: @env.fetch("JIRA_EMAIL"),
91
+ api_token: @env.fetch("JIRA_API_TOKEN")
92
+ )
93
+ end
94
+
95
+ def fail_with(message)
96
+ @err.puts(message)
97
+ 1
98
+ end
99
+
100
+ def option_names(keys)
101
+ keys.map { |key| "--#{key.to_s.tr("_", "-")}" }.join(", ")
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Marlens
4
+ module GithubToJiraComment
5
+ class CommentPoster
6
+ DEFAULT_IMAGE_HOSTS = ["private-user-images.githubusercontent.com"].freeze
7
+
8
+ def initialize(jira_client:)
9
+ @jira_client = jira_client
10
+ end
11
+
12
+ def post(jira_url:, markdown:, allowed_image_hosts: DEFAULT_IMAGE_HOSTS)
13
+ create(
14
+ issue_key: JiraUrl.parse(jira_url).issue_key,
15
+ markdown:,
16
+ allowed_image_hosts:
17
+ )
18
+ end
19
+
20
+ def create(issue_key:, markdown:, allowed_image_hosts: [])
21
+ @jira_client.create_markdown_comment(
22
+ issue_key:,
23
+ markdown:,
24
+ allowed_image_hosts:,
25
+ strict_images: true,
26
+ image_upload_failures: []
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "net/http"
5
+ require "uri"
6
+
7
+ module Marlens
8
+ module GithubToJiraComment
9
+ class GithubClient
10
+ Content = Struct.new(:title, :body, keyword_init: true)
11
+
12
+ API_ROOT = "https://api.github.com"
13
+
14
+ def initialize(token:, http: nil, requester: nil)
15
+ @token = token
16
+ @http = http
17
+ @requester = requester || method(:request)
18
+ end
19
+
20
+ def fetch(source)
21
+ source = GithubUrl.parse(source) if source.is_a?(String)
22
+ json = get_json(source.api_path)
23
+ Content.new(title: json.fetch("title"), body: json["body"].to_s)
24
+ end
25
+
26
+ def render_markdown(markdown, context:)
27
+ uri = URI("#{API_ROOT}/markdown")
28
+ request = Net::HTTP::Post.new(uri)
29
+ request.body = JSON.dump("text" => markdown, "mode" => "gfm", "context" => context)
30
+ response = perform(uri, request)
31
+ return response.body if response.code.to_i.between?(200, 299)
32
+
33
+ raise "GitHub Markdown render failed: #{response.code} #{response.body}"
34
+ end
35
+
36
+ private
37
+
38
+ def get_json(path)
39
+ return @http.get(path, headers:) if @http
40
+
41
+ uri = URI("#{API_ROOT}#{path}")
42
+ response = perform(uri, Net::HTTP::Get.new(uri))
43
+ return JSON.parse(response.body) if response.code.to_i.between?(200, 299)
44
+
45
+ raise "GitHub API request failed: #{response.code} #{response.body}"
46
+ end
47
+
48
+ def perform(uri, request)
49
+ headers.each { |key, value| request[key] = value }
50
+ request["Content-Type"] = "application/json" if request.request_body_permitted?
51
+ @requester.call(uri, request)
52
+ end
53
+
54
+ def headers
55
+ {
56
+ "Accept" => "application/vnd.github+json",
57
+ "Authorization" => "Bearer #{@token}",
58
+ }
59
+ end
60
+
61
+ def request(uri, request)
62
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
63
+ http.request(request)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "commonmarker"
4
+ require "uri"
5
+
6
+ module Marlens
7
+ module GithubToJiraComment
8
+ class GithubMarkdownResolver
9
+ Result = Struct.new(:markdown, :allowed_image_hosts, keyword_init: true)
10
+ Image = Struct.new(:url, keyword_init: true)
11
+
12
+ MARKDOWN_IMAGE = /!\[[^\]]*\]\(([^)\s]+)(\s+"[^"]*")?\)/
13
+ HTML_IMAGE = /<img\b(?<attributes>[^>]+)>/i
14
+
15
+ def initialize(github_client: nil, renderer: nil)
16
+ @github_client = github_client
17
+ @renderer = renderer
18
+ end
19
+
20
+ def resolve(markdown, context: nil)
21
+ resolve_with_metadata(markdown, context:).markdown
22
+ end
23
+
24
+ def resolve_with_metadata(markdown, context: nil)
25
+ images = image_occurrences(markdown)
26
+ attachment_images = images.select { |image| github_user_attachment?(image.url) }
27
+ return Result.new(markdown:, allowed_image_hosts: []) if attachment_images.empty?
28
+
29
+ rendered_images = rendered_image_urls(render_markdown(markdown, context:)).select { |url| rendered_attachment?(url) }
30
+ mappings = {}
31
+ attachment_images.each_with_index do |image, index|
32
+ rendered = rendered_images[index] || mappings[image.url]
33
+ raise "GitHub Markdown render did not return an image for #{image.url}" unless rendered
34
+
35
+ mappings[image.url] ||= rendered
36
+ end
37
+
38
+ resolved = rewrite_image_urls(markdown, mappings)
39
+ Result.new(markdown: resolved, allowed_image_hosts: mappings.values.filter_map { |url| host(url) }.uniq)
40
+ end
41
+
42
+ private
43
+
44
+ def render_markdown(markdown, context:)
45
+ return @renderer.render(markdown) if @renderer
46
+
47
+ @github_client.render_markdown(markdown, context:)
48
+ end
49
+
50
+ def image_occurrences(markdown)
51
+ images = []
52
+ collect_images(markdown_document(markdown), images)
53
+ images
54
+ end
55
+
56
+ def rewrite_image_urls(markdown, mappings)
57
+ fenced = false
58
+ markdown.each_line.map do |line|
59
+ if line.match?(/\A\s*(```|~~~)/)
60
+ fenced = !fenced
61
+ next line
62
+ end
63
+ next line if fenced
64
+
65
+ line
66
+ .gsub(MARKDOWN_IMAGE) { |match| mappings.key?($1) ? match.sub($1, mappings.fetch($1)) : match }
67
+ .gsub(HTML_IMAGE) { |match| rewrite_html_image(match, mappings) }
68
+ end.join
69
+ end
70
+
71
+ def rewrite_html_image(tag, mappings)
72
+ url = html_image_url(tag)
73
+ return tag unless mappings.key?(url)
74
+
75
+ tag.sub(url, mappings.fetch(url))
76
+ end
77
+
78
+ def collect_images(node, images)
79
+ case node.type
80
+ when :image
81
+ images << Image.new(url: node.url)
82
+ when :html_inline, :html_block
83
+ html_image_url(node.to_commonmark)&.then { |url| images << Image.new(url:) }
84
+ end
85
+
86
+ node.each { |child| collect_images(child, images) }
87
+ end
88
+
89
+ def markdown_document(markdown)
90
+ Commonmarker.parse(
91
+ markdown,
92
+ options: {
93
+ parse: { smart: true },
94
+ extension: { autolink: true, strikethrough: true, table: true, tagfilter: false },
95
+ }
96
+ )
97
+ end
98
+
99
+ def rendered_image_urls(html)
100
+ html.scan(HTML_IMAGE).filter_map do |match|
101
+ parse_html_attributes(match.first)["src"]
102
+ end
103
+ end
104
+
105
+ def html_image_url(html)
106
+ match = html.match(HTML_IMAGE)
107
+ return nil unless match
108
+
109
+ parse_html_attributes(match[:attributes])["src"]
110
+ end
111
+
112
+ def parse_html_attributes(attributes)
113
+ attributes.scan(/([a-zA-Z:-]+)=["']([^"']+)["']/).to_h
114
+ end
115
+
116
+
117
+ def rendered_attachment?(url)
118
+ uri = URI.parse(url)
119
+ uri.host == "private-user-images.githubusercontent.com" || github_user_attachment?(url)
120
+ rescue URI::InvalidURIError
121
+ false
122
+ end
123
+ def github_user_attachment?(url)
124
+ uri = URI.parse(url)
125
+ uri.scheme == "https" && uri.host == "github.com" && uri.path.start_with?("/user-attachments/assets/")
126
+ rescue URI::InvalidURIError
127
+ false
128
+ end
129
+
130
+ def host(url)
131
+ URI.parse(url).host
132
+ rescue URI::InvalidURIError
133
+ nil
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module Marlens
6
+ module GithubToJiraComment
7
+ class GithubUrl
8
+ Source = Struct.new(:owner, :repo, :type, :number, keyword_init: true) do
9
+ def api_path
10
+ collection = type == "pull" ? "pulls" : "issues"
11
+ "/repos/#{owner}/#{repo}/#{collection}/#{number}"
12
+ end
13
+
14
+ def context
15
+ "#{owner}/#{repo}"
16
+ end
17
+ end
18
+
19
+ def self.parse(url)
20
+ uri = URI.parse(url)
21
+ segments = uri.path.split("/").reject(&:empty?)
22
+ unless uri.is_a?(URI::HTTPS) && uri.host == "github.com" && segments.length == 4
23
+ raise ArgumentError, "GitHub URL must be https://github.com/<owner>/<repo>/pull/<number> or /issues/<number>"
24
+ end
25
+
26
+ owner, repo, path_type, number = segments
27
+ unless %w[pull issues].include?(path_type) && number.match?(/\A\d+\z/)
28
+ raise ArgumentError, "GitHub URL must point to a pull request or issue number"
29
+ end
30
+
31
+ Source.new(owner:, repo:, type: path_type == "pull" ? "pull" : "issue", number:)
32
+ rescue URI::InvalidURIError
33
+ raise ArgumentError, "Invalid GitHub URL"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module Marlens
6
+ module GithubToJiraComment
7
+ class JiraUrl
8
+ Issue = Struct.new(:base_url, :issue_key, keyword_init: true)
9
+
10
+ def self.parse(url)
11
+ uri = URI.parse(url)
12
+ match = uri.path.match(%r{\A/browse/([A-Z][A-Z0-9_]*-\d+)\z})
13
+ unless uri.is_a?(URI::HTTPS) && uri.host&.end_with?(".atlassian.net") && match
14
+ raise ArgumentError, "Jira URL must be https://<site>.atlassian.net/browse/<ISSUE-KEY>"
15
+ end
16
+
17
+ Issue.new(base_url: "#{uri.scheme}://#{uri.host}", issue_key: match[1])
18
+ rescue URI::InvalidURIError
19
+ raise ArgumentError, "Invalid Jira URL"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Marlens
4
+ module GithubToJiraComment
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "github_to_jira_comment/version"
4
+ require_relative "github_to_jira_comment/github_url"
5
+ require_relative "github_to_jira_comment/jira_url"
6
+ require_relative "github_to_jira_comment/github_client"
7
+ require_relative "github_to_jira_comment/github_markdown_resolver"
8
+ require_relative "github_to_jira_comment/comment_poster"
9
+ require_relative "github_to_jira_comment/cli"
10
+
11
+ module Marlens
12
+ module GithubToJiraComment
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: marlens-github-to-jira-comment
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Marlen Brunner
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: marlens-jira-api
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.5'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.5'
26
+ - !ruby/object:Gem::Dependency
27
+ name: commonmarker
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.8'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.8'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rspec
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.13'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.13'
54
+ description: Small CLI/gem bridge from full GitHub issue/pull request URLs to full
55
+ Jira issue URLs.
56
+ email:
57
+ - klondike.marlen@gmail.com
58
+ executables:
59
+ - github-to-jira-comment
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - LICENSE.txt
64
+ - README.md
65
+ - bin/github-to-jira-comment
66
+ - lib/marlens/github_to_jira_comment.rb
67
+ - lib/marlens/github_to_jira_comment/cli.rb
68
+ - lib/marlens/github_to_jira_comment/comment_poster.rb
69
+ - lib/marlens/github_to_jira_comment/github_client.rb
70
+ - lib/marlens/github_to_jira_comment/github_markdown_resolver.rb
71
+ - lib/marlens/github_to_jira_comment/github_url.rb
72
+ - lib/marlens/github_to_jira_comment/jira_url.rb
73
+ - lib/marlens/github_to_jira_comment/version.rb
74
+ homepage: https://github.com/klondikemarlen/github-to-jira-comment
75
+ licenses:
76
+ - MIT
77
+ metadata:
78
+ homepage_uri: https://github.com/klondikemarlen/github-to-jira-comment
79
+ source_code_uri: https://github.com/klondikemarlen/github-to-jira-comment
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '3.2'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubygems_version: 4.0.10
95
+ specification_version: 4
96
+ summary: Copy GitHub issue or pull request bodies into Jira comments.
97
+ test_files: []