marlens-jira-api 0.5.1 → 0.5.2

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: 4d03091de06691a2493443796b27c4c7205067ba92eb3503cdf0ccb2771b86a6
4
- data.tar.gz: 0f1c94a08e018b97a171a25a888baabebb301a9427f9f6eccc915e8b222fad7a
3
+ metadata.gz: 89d099771b89c4a51659eaca4c4242d7102762ec507e4d80265ce2e1612d756c
4
+ data.tar.gz: 93682e74950ac69b58316049b1251f61eb6f1a8eed75d7d14695585da4ad45d9
5
5
  SHA512:
6
- metadata.gz: a47ff4083694ad1406d0248b4ac86afead42c425464c2cfeb0fb61f9d344aed3c8a78172fae723095d02f09ea0cdc9343cfac0d9394388cfa490a646449900bc
7
- data.tar.gz: 51e132f5fa0b5f3e59fb6ebb35c37d8fd9ec468bab881dbca2fb7bc191cd210a9adc1055ac9173fc1200ab27b05ec49824c1468a9786414a7db6e64b2f8e8c2d
6
+ metadata.gz: 20e4b6ecd4f692d4c9b699f1ed4d0a3fe2f3ae5be5de2bb7970c540efacdbd08ec45a9dd9384184fb38300b23d5ac07dd0adec482eb93025ec9f8d8d6e28ecfb
7
+ data.tar.gz: ad230b1e8235738fecc90762794c5e8ca2fd07f62fa3d551c2f47eca630177676c3d04e5af53e7d5f699f6ce1ce9ff511971b037cef1e01c663b21a08f2ae98c
data/README.md CHANGED
@@ -50,6 +50,8 @@ jira-comment delete --issue-key WRAPX-123 --comment-id 10001
50
50
 
51
51
  Remote Markdown image URLs are advanced opt-in behavior. Pass `allowed_image_hosts:` in Ruby or repeat `--image-host` in the CLI only when you intentionally want the gem to fetch images from trusted hosts, upload them to Jira, and convert them into Jira media attachments.
52
52
 
53
+ Ruby callers that need to detect degraded images can pass an array via `image_upload_failures:`. Add `strict_images: true` in Ruby or `--strict-images` in the CLI to raise `Marlens::JiraApi::ImageUploadError` instead of falling back to `Alt text: URL` when an image cannot be fetched or uploaded.
54
+
53
55
  ## Feature and Issue Workflow
54
56
 
55
57
  Preferred flow for issue and feature work:
@@ -61,4 +63,6 @@ Preferred flow for issue and feature work:
61
63
  5. Open a draft PR, link the issue, include the checks run, and mark it ready only after verification.
62
64
  6. Merge the PR to `main` so GitHub records the review path.
63
65
  7. After merge, build and publish the gem version to RubyGems with `gem build marlens-jira-api.gemspec` and `gem push marlens-jira-api-<version>.gem`.
64
- 8. Verify RubyGems lists the released version with `gem list --remote marlens-jira-api --exact --all`, then run an install or CLI smoke check.
66
+ 8. Verify RubyGems lists the released version with `gem list --remote marlens-jira-api --exact --all`; if that output is stale, verify the specific version API at `https://rubygems.org/api/v2/rubygems/marlens-jira-api/versions/<version>.json`.
67
+ 9. Run an install or CLI smoke check against the published gem.
68
+ 10. Keep one-off smoke cleanup helpers in `tmp/`, delete them before committing, and do not turn cleanup-only scripts into product API.
@@ -37,14 +37,14 @@ module Marlens
37
37
 
38
38
  @out.puts JSON.pretty_generate(send(config.fetch(:action), options))
39
39
  0
40
- rescue OptionParser::ParseError, KeyError => error
40
+ rescue OptionParser::ParseError, KeyError, ImageUploadError => error
41
41
  fail_with(error.message)
42
42
  end
43
43
 
44
44
  private
45
45
 
46
46
  def parse_options
47
- options = { allowed_image_hosts: [] }
47
+ options = { allowed_image_hosts: [], strict_images: false }
48
48
  parser = OptionParser.new do |parser|
49
49
  parser.banner = "Usage: jira-comment [#{COMMANDS.keys.join("|")}] [options]"
50
50
  parser.on("--issue-key ISSUE", "Jira issue key") { |value| options[:issue_key] = value }
@@ -53,6 +53,9 @@ module Marlens
53
53
  parser.on("--image-host HOST", "Allowed remote image host; repeatable") do |value|
54
54
  options[:allowed_image_hosts] << value
55
55
  end
56
+ parser.on("--strict-images", "Fail create/update when a remote image cannot be uploaded") do
57
+ options[:strict_images] = true
58
+ end
56
59
  end
57
60
  parser.parse!(@argv)
58
61
  options
@@ -67,20 +70,28 @@ module Marlens
67
70
  end
68
71
 
69
72
  def create_comment(options)
70
- client.create_markdown_comment(
73
+ image_upload_failures = []
74
+ result = client.create_markdown_comment(
71
75
  issue_key: options.fetch(:issue_key),
72
76
  markdown: File.read(options.fetch(:markdown_file)),
73
- allowed_image_hosts: options.fetch(:allowed_image_hosts)
77
+ allowed_image_hosts: options.fetch(:allowed_image_hosts),
78
+ strict_images: options.fetch(:strict_images),
79
+ image_upload_failures: image_upload_failures
74
80
  )
81
+ result_with_image_failures(result, image_upload_failures)
75
82
  end
76
83
 
77
84
  def update_comment(options)
78
- client.update_markdown_comment(
85
+ image_upload_failures = []
86
+ result = client.update_markdown_comment(
79
87
  issue_key: options.fetch(:issue_key),
80
88
  comment_id: options.fetch(:comment_id),
81
89
  markdown: File.read(options.fetch(:markdown_file)),
82
- allowed_image_hosts: options.fetch(:allowed_image_hosts)
90
+ allowed_image_hosts: options.fetch(:allowed_image_hosts),
91
+ strict_images: options.fetch(:strict_images),
92
+ image_upload_failures: image_upload_failures
83
93
  )
94
+ result_with_image_failures(result, image_upload_failures)
84
95
  end
85
96
 
86
97
  def delete_comment(options)
@@ -88,6 +99,12 @@ module Marlens
88
99
  { deleted: true }
89
100
  end
90
101
 
102
+ def result_with_image_failures(result, image_upload_failures)
103
+ return result if image_upload_failures.empty?
104
+
105
+ result.merge("image_upload_failures" => image_upload_failures)
106
+ end
107
+
91
108
  def client
92
109
  @client ||= @client_factory.call(env: @env)
93
110
  end
@@ -54,20 +54,24 @@ module Marlens
54
54
  raise "Failed to delete Jira comment #{comment_id} for #{issue_key}: #{response.code} #{response.body}"
55
55
  end
56
56
 
57
- def create_markdown_comment(issue_key:, markdown:, allowed_image_hosts: [])
57
+ def create_markdown_comment(issue_key:, markdown:, allowed_image_hosts: [], strict_images: false, image_upload_failures: nil)
58
58
  document = markdown_document(
59
59
  issue_key: issue_key,
60
60
  markdown: markdown,
61
- allowed_image_hosts: allowed_image_hosts
61
+ allowed_image_hosts: allowed_image_hosts,
62
+ strict_images: strict_images,
63
+ image_upload_failures: image_upload_failures
62
64
  )
63
65
  create_comment(issue_key: issue_key, document: document)
64
66
  end
65
67
 
66
- def update_markdown_comment(issue_key:, comment_id:, markdown:, allowed_image_hosts: [])
68
+ def update_markdown_comment(issue_key:, comment_id:, markdown:, allowed_image_hosts: [], strict_images: false, image_upload_failures: nil)
67
69
  document = markdown_document(
68
70
  issue_key: issue_key,
69
71
  markdown: markdown,
70
- allowed_image_hosts: allowed_image_hosts
72
+ allowed_image_hosts: allowed_image_hosts,
73
+ strict_images: strict_images,
74
+ image_upload_failures: image_upload_failures
71
75
  )
72
76
  update_comment(issue_key: issue_key, comment_id: comment_id, document: document)
73
77
  end
@@ -94,11 +98,13 @@ module Marlens
94
98
 
95
99
  private
96
100
 
97
- def markdown_document(issue_key:, markdown:, allowed_image_hosts:)
101
+ def markdown_document(issue_key:, markdown:, allowed_image_hosts:, strict_images:, image_upload_failures:)
98
102
  image_uploader = RemoteImageAttachmentUploader.new(
99
103
  client: self,
100
104
  issue_key: issue_key,
101
- allowed_hosts: allowed_image_hosts
105
+ allowed_hosts: allowed_image_hosts,
106
+ strict: strict_images,
107
+ failures: image_upload_failures
102
108
  )
103
109
  MarkdownToAdf.call(markdown) do |image|
104
110
  image_uploader.media_node_for(image)
@@ -7,13 +7,24 @@ require "uri"
7
7
 
8
8
  module Marlens
9
9
  module JiraApi
10
+ class ImageUploadError < StandardError
11
+ attr_reader :failure
12
+
13
+ def initialize(failure)
14
+ @failure = failure
15
+ super("Failed to upload image #{failure.fetch(:url)}: #{failure.fetch(:error_class)}: #{failure.fetch(:error_message)}")
16
+ end
17
+ end
18
+
10
19
  class RemoteImageAttachmentUploader
11
20
  MAX_REDIRECTS = 5
12
21
 
13
- def initialize(client:, issue_key:, allowed_hosts:)
22
+ def initialize(client:, issue_key:, allowed_hosts:, strict: false, failures: nil)
14
23
  @allowed_hosts = allowed_hosts
15
24
  @client = client
25
+ @failures = failures
16
26
  @issue_key = issue_key
27
+ @strict = strict
17
28
  end
18
29
 
19
30
  def media_node_for(image)
@@ -27,6 +38,10 @@ module Marlens
27
38
  height: image_dimension_value(image[:height], dimensions.fetch("height"))
28
39
  )
29
40
  rescue StandardError => error
41
+ failure = { url: image[:url], alt: image[:alt], error_class: error.class.name, error_message: error.message }
42
+ @failures << failure if @failures
43
+ raise ImageUploadError.new(failure) if @strict
44
+
30
45
  warn "Failed to upload image #{image[:url]}: #{error.class}: #{error.message}"
31
46
  MarkdownToAdf.paragraph("#{image[:alt] || "Image"}: #{image[:url]}")
32
47
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Marlens
4
4
  module JiraApi
5
- VERSION = "0.5.1"
5
+ VERSION = "0.5.2"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marlens-jira-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marlen Brunner