-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathissue.rb
More file actions
153 lines (126 loc) · 4.75 KB
/
issue.rb
File metadata and controls
153 lines (126 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# frozen_string_literal: true
require 'gqli'
module Rubyists
# Namespace for Linear
module Linear
M :base_model
Issue = Class.new(BaseModel)
M 'issue/class_methods'
# The Issue class represents a Linear issue.
class Issue
include SemanticLogger::Loggable
extend ClassMethods
many_to_one :assignee, :User
many_to_one :team
one_to_many :comments
BASIC_FILTER = { completedAt: { null: true }, canceledAt: { null: true } }.freeze
Base = fragment('BaseIssue', 'Issue') do
id
identifier
title
branchName
description
createdAt
updatedAt
end
def comment_fragment
@comment_fragment ||= fragment('Comment', 'Comment') do
id
body
url
end
end
def update!(input)
id_for_this = identifier
m = mutation { issueUpdate(id: id_for_this, input:) { issue { ___ Issue.full_fragment } } }
query_data = Api.query(m)
updated = query_data.dig(:issueUpdate, :issue)
raise SmellsBad, "Unknown response for issue update: #{data} (should have :issueUpdate key)" if updated.nil?
@data = @updated_data = updated
self
end
def attach_to_project(project)
update!({ projectId: project.id })
end
# Reference for this mutation:
# https://studio.apollographql.com/public/Linear-API/variant/current/schema/reference/inputs/CommentCreateInput
def add_comment(comment)
id_for_this = identifier
comment_frag = comment_fragment
m = mutation { commentCreate(input: { issueId: id_for_this, body: comment }) { comment { ___ comment_frag } } }
query_data = Api.query(m)
query_data.dig(:commentCreate, :comment)
self
end
def close_mutation(close_state, trash: false)
id_for_this = identifier
input = { stateId: close_state.id }
input[:trashed] = true if trash
mutation { issueUpdate(id: id_for_this, input:) { issue { ___ Issue.full_fragment } } }
end
def close!(state: nil, trash: false) # rubocop:disable Metrics/MethodLength
logger.warn "Using first completed state found: #{completed_states.first}" if state.nil?
state ||= completed_states.first
query_data = Api.query close_mutation(state, trash:)
unless query_data.respond_to?(:dig)
raise SmellsBad, "Unknown response (#{query_data || "NULL"}) updating #{self} to #{state}, trash: #{trash}"
end
updated = query_data.dig(:issueUpdate, :issue)
if updated.nil?
raise SmellsBad, "Unknown response for issue close: #{query_data} (should have :issueUpdate key)"
end
@data = @updated_data = updated
self
end
def assign!(user)
this_id = identifier
m = mutation { issueUpdate(id: this_id, input: { assigneeId: user.id }) { issue { ___ Issue.full_fragment } } }
query_data = Api.query(m)
updated = query_data.dig(:issueUpdate, :issue)
raise SmellsBad, "Unknown response for issue update: #{data} (should have :issueUpdate key)" if updated.nil?
@data = @updated_data = updated
self
end
def workflow_states
@workflow_states ||= team.workflow_states
end
def inspection
format('id: "%<identifier>s" title: "%<title>s"', identifier:, title:)
end
def to_s
basic = format('%<id>-12s %<title>s', id: identifier, title:)
return basic unless (name = data.dig(:assignee, :name))
format('%<basic>s (%<name>s)', basic:, name:)
end
def parsed_description
return TTY::Markdown.parse(description) if description && !description.empty?
TTY::Markdown.parse(['# No Description For this issue??',
'Issues really need description',
"## What's up with that?"].join("\n"))
rescue StandardError => e
logger.error 'Error parsing description', e
"Description was unparsable: #{description}\n"
end
def display_comments
return '' unless comments.respond_to?(:map)
displays = comments&.map do |c|
user = c.user.name
date = DateTime.parse(c.createdAt).strftime('%Y-%m-%d at %H:%M')
"--- #{user} on #{date} ---\n#{TTY::Markdown.parse(c.body)}"
end
displays&.join("\n")
end
def full
sep = '-' * to_s.length
format("%<to_s>s\n%<sep>s\n%<description>s\n%<comments>s",
sep:,
to_s:,
description: parsed_description,
comments: display_comments)
end
def display(options)
printf "%s\n", (options[:full] ? full : to_s)
end
end
end
end