trellohub 0.0.1 → 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.
@@ -0,0 +1,142 @@
1
+ require 'trellohub/form/card'
2
+ require 'trellohub/form/issue'
3
+
4
+ module Trellohub
5
+ class Form
6
+ include Form::Card
7
+ include Form::Issue
8
+
9
+ class << self
10
+ def common_attributes
11
+ %i(
12
+ key
13
+ state
14
+ imported_from
15
+ )
16
+ end
17
+
18
+ def origin_attributes
19
+ %i(
20
+ origin_issue
21
+ origin_card
22
+ )
23
+ end
24
+
25
+ def array_ext
26
+ <<-METHODS
27
+ def find_by_key(key)
28
+ self.find { |form| form.key == key }
29
+ end
30
+ METHODS
31
+ end
32
+
33
+ def with_issues
34
+ @issues ||= self.with_issues!
35
+ end
36
+
37
+ def with_issues!
38
+ array = Trellohub.repositories.each.with_object([]) do |repo, forms|
39
+ forms.concat with_issues_on(repo)
40
+ end
41
+ array.instance_eval array_ext
42
+ array
43
+ end
44
+
45
+ def with_issues_on(repo)
46
+ repo.issues.each.with_object([]) do |issue, forms|
47
+ form = Trellohub::Form.new
48
+ form.import_issue repo.full_name, issue
49
+ forms << form
50
+ end
51
+ end
52
+
53
+ def with_cards
54
+ @cards ||= self.with_cards!
55
+ end
56
+
57
+ def with_cards!
58
+ array = Trellohub::Card.all.
59
+ each.with_object([]) do |card, forms|
60
+ form = Trellohub::Form.new
61
+ form.import_card card
62
+ forms << form
63
+ end
64
+ array.instance_eval array_ext
65
+ array
66
+ end
67
+
68
+ def compare(base, target)
69
+ return unless base.updated_at < target.updated_at
70
+ type = target.imported_from
71
+
72
+ printings = [[
73
+ "#{type} attribute",
74
+ "#{'base'.green} (#{base.imported_from}: #{base.own_key}, #{base.updated_at})",
75
+ "#{'comparison'.yellow} (#{target.imported_from}: #{target.own_key}, #{target.updated_at})"
76
+ ]] if Trellohub.debug
77
+
78
+ diff = target.send(:"to_valid_#{type}").each.with_object({}) do |(key, value), hash|
79
+ base_value = base.send(:"to_valid_#{type}")[key]
80
+ hash[key] = value unless value == base_value
81
+
82
+ printings << [
83
+ key,
84
+ base_value.to_s.color(value == base_value ? :green : :red),
85
+ value.to_s.yellow
86
+ ] if Trellohub.debug
87
+ end
88
+
89
+ if Trellohub.debug && !diff.empty?
90
+ max = printings.max_lengths
91
+ printings.each.with_index(1) do |line, index|
92
+ puts '[DIFF: Update the base]' if index == 1
93
+ puts 3.times.map.with_index { |i| ''.ljust(max[i], '-') }.join(' | ') if index == 2
94
+ puts line.map.with_index { |word, i| "#{word}".ljust(max[i]) }.join(' | ')
95
+ end
96
+ end
97
+
98
+ diff unless diff.empty?
99
+ end
100
+ end
101
+
102
+ attr_accessor(*self.common_attributes + self.origin_attributes)
103
+
104
+ def created_at
105
+ @created_at ||= send(:"#{@imported_from}_#{__method__}")
106
+ end
107
+
108
+ def updated_at
109
+ return @issue_updated_at if @imported_from == :issue
110
+ @updated_at ||= card_updated_at || card_created_at
111
+ end
112
+
113
+ def closed_at
114
+ return @issue_closed_at if @imported_from == :issue
115
+ @closed_at ||= card_closed_at || card_created_at
116
+ end
117
+
118
+ def open?
119
+ @state == 'open'
120
+ end
121
+
122
+ def closed?
123
+ @state == 'closed'
124
+ end
125
+
126
+ def own_key
127
+ if @imported_from == :issue
128
+ @key
129
+ else
130
+ @card_shortLink
131
+ end
132
+ end
133
+
134
+ def to_hash
135
+ Hash[instance_variables.map { |variable|
136
+ next if variable.is_a?(Sawyer::Resource)
137
+ variable_no_at = variable.to_s.gsub('@', '')
138
+ [variable_no_at.to_sym, instance_variable_get(:"#{variable}")]
139
+ }.compact]
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,163 @@
1
+ module Trellohub
2
+ class Form
3
+ module Card
4
+ class << self
5
+ def valid_attributes
6
+ %i(
7
+ closed
8
+ desc
9
+ idBoard
10
+ idList
11
+ name
12
+ idMembers
13
+ )
14
+ end
15
+
16
+ def accessible_attributes
17
+ self.prefix(self.valid_attributes + %i(list_name))
18
+ end
19
+
20
+ def readable_attributes
21
+ self.prefix %i(labels)
22
+ end
23
+
24
+ def prefix(array)
25
+ array.map { |key| :"card_#{key}" }
26
+ end
27
+
28
+ def included(base)
29
+ base.class_eval do
30
+ attr_accessor(*Trellohub::Form::Card.accessible_attributes)
31
+ attr_reader(*Trellohub::Form::Card.readable_attributes)
32
+ end
33
+ end
34
+ end
35
+
36
+ def import_card(card)
37
+ @origin_card = card.dup
38
+ @imported_from = :card
39
+
40
+ card.attrs.keys.each do |key|
41
+ next if key == :badges
42
+ instance_variable_set(:"@card_#{key}", card.send(key))
43
+ end
44
+
45
+ build_card_attributes_by_card
46
+ build_issue_attributes_by_card
47
+ end
48
+
49
+ # e.g.
50
+ # => #<MatchData
51
+ # "synced_issue: https://github.com/linyows-Z_2/trellohub-foo_aaa-123/issues/127"
52
+ # 1:"linyows-Z_2/trellohub-foo_aaa-123"
53
+ # 2:"127">
54
+ def key_matcher
55
+ /synced_issue:\shttps?:\/\/.*?\/([\w\-\/]+)\/(?:issues|pulls)\/(\d+)/
56
+ end
57
+
58
+ def card_name_prefix_matcher
59
+ /^[\w\-]+#\d+\s/
60
+ end
61
+
62
+ def build_card_attributes_by_card
63
+ list = Trellohub::List.find_by(id: @origin_card.idList)
64
+ @card_list_name = list.name if list
65
+ end
66
+
67
+ def build_issue_attributes_by_card
68
+ @issue_title = @origin_card.name.gsub(card_name_prefix_matcher, '')
69
+ @issue_state = @state = @origin_card.closed ? 'closed' : 'open'
70
+
71
+ if @origin_card.desc =~ key_matcher
72
+ @issue_repository = $1
73
+ @issue_number = $2
74
+ @key = "#{$1}##{$2}"
75
+
76
+ repo = Trellohub.repository_by(full_name: @issue_repository)
77
+ @issue_milestone = repo.milestone.title if repo.milestone?
78
+ end
79
+
80
+ unless @origin_card.idMembers.empty?
81
+ member = Trellohub::Member.find_by(id: @origin_card.idMembers.first)
82
+ @issue_assignee = member.username if member
83
+ end
84
+
85
+ if @card_list_name
86
+ label = Trellohub.list_by(name: @card_list_name).issue_label
87
+ @issue_labels = label ? [label] : []
88
+ end
89
+ end
90
+
91
+ %i(create update delete).each do |cud|
92
+ class_eval <<-METHODS, __FILE__, __LINE__ + 1
93
+ def card_#{cud}d_at
94
+ return if @card_id.nil?
95
+ card_#{cud}_action.date if card_#{cud}_action
96
+ end
97
+
98
+ def card_#{cud}_user
99
+ return if @card_id.nil?
100
+ if card_#{cud}_action && card_#{cud}_action.memberCreator
101
+ card_#{cud}_action.memberCreator.username
102
+ end
103
+ end
104
+
105
+ def card_#{cud}_action
106
+ return if @card_id.nil?
107
+ @card_#{cud}_action ||= Trell.card_actions(@card_id, filter: '#{cud}Card').
108
+ sort_by(&:date).last
109
+ rescue Trell::NotFound
110
+ end
111
+ METHODS
112
+ end
113
+
114
+ def card_id
115
+ if @card_id.nil? && @imported_from == :issue
116
+ form = Trellohub::Form.with_cards.find_by_key(@key)
117
+ @card_id = form.card_id if form
118
+ end
119
+
120
+ @card_id
121
+ end
122
+
123
+ def card_update?
124
+ !card_id.nil?
125
+ end
126
+
127
+ def create_card
128
+ Trell.create_card(to_valid_card)
129
+ end
130
+
131
+ def update_card
132
+ Trell.update_card(@card_id, to_valid_card)
133
+ end
134
+
135
+ def close_card
136
+ Trell.update_card(@card_id, to_valid_card.merge(closed: true))
137
+ end
138
+
139
+ def save_as_card
140
+ case
141
+ when card_update? && open? then update_card
142
+ when card_update? && closed? then close_card
143
+ when open? then create_card
144
+ end
145
+ end
146
+
147
+ def to_valid_card
148
+ Hash[Trellohub::Form::Card.valid_attributes.map { |key|
149
+ [key, instance_variable_get(:"@card_#{key}")]
150
+ }]
151
+ end
152
+
153
+ def to_card
154
+ Hash[Trellohub::Form::Card.accessible_attributes.map { |key|
155
+ [
156
+ key.to_s.gsub('card_', '').to_sym,
157
+ instance_variable_get(:"@#{key}")
158
+ ]
159
+ }]
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,191 @@
1
+ module Trellohub
2
+ class Form
3
+ module Issue
4
+ class << self
5
+ def valid_attributes
6
+ %i(
7
+ title
8
+ labels
9
+ state
10
+ assignee
11
+ )
12
+ end
13
+
14
+ def accessible_attributes
15
+ self.prefix self.valid_attributes
16
+ end
17
+
18
+ def readable_attributes
19
+ self.prefix %i(
20
+ number
21
+ created_at
22
+ updated_at
23
+ closed_at
24
+ )
25
+ end
26
+
27
+ def prefix(array)
28
+ array.map { |key| :"issue_#{key}" }
29
+ end
30
+
31
+ def included(base)
32
+ base.class_eval do
33
+ attr_accessor(*Trellohub::Form::Issue.accessible_attributes)
34
+ attr_reader(*Trellohub::Form::Issue.readable_attributes)
35
+ end
36
+ end
37
+ end
38
+
39
+ def import_issue(repository, issue)
40
+ @origin_issue = issue.dup
41
+ @issue_repository = repository
42
+ @key = "#{repository}##{@origin_issue.number}"
43
+ @state = @origin_issue.state
44
+ @imported_from = :issue
45
+
46
+ build_card_attributes_by_issue
47
+ build_issue_attributes_by_issue
48
+ end
49
+
50
+ def build_card_attributes_by_issue
51
+ @card_idBoard = Trellohub::Board.id
52
+ @card_name = "#{issue_repo_name}##{@origin_issue.number} #{@origin_issue.title}"
53
+ @card_desc = "synced_issue: #{Octokit.web_endpoint}#{@issue_repository}/issues/#{@origin_issue.number}"
54
+ @card_closed = @origin_issue.state == 'closed'
55
+ assign_card_members_by_issue
56
+ assign_card_list_by_issue
57
+ end
58
+
59
+ def build_issue_attributes_by_issue
60
+ @origin_issue.attrs.keys.each do |key|
61
+ next if key == :pull_request
62
+
63
+ value = case key
64
+ when :user
65
+ @origin_issue.user.login
66
+ when :assignee
67
+ @origin_issue.assignee ? @origin_issue.assignee.login : nil
68
+ when :labels
69
+ @origin_issue.labels.empty? ? [] : @origin_issue.labels.map(&:name)
70
+ else
71
+ @origin_issue.send(key)
72
+ end
73
+
74
+ instance_variable_set(:"@issue_#{key}", value)
75
+ end
76
+
77
+ @issue_id = @origin_issue.id
78
+ @issue_number = @origin_issue.number
79
+
80
+ if @origin_issue.milestone
81
+ @issue_milestone_title = @origin_issue.milestone.title
82
+ @issue_milestone = @origin_issue.milestone.number
83
+ end
84
+ end
85
+
86
+ def issue_repository_name
87
+ @issue_repository.split('/').last
88
+ end
89
+ alias_method :issue_repo_name, :issue_repository_name
90
+
91
+ def assign_card_members_by_issue
92
+ @card_idMembers = []
93
+ return unless @origin_issue.assignee
94
+
95
+ member = Trellohub::Member.find_by(username: @origin_issue.assignee.login)
96
+ unless member.nil?
97
+ @card_idMembers << member.id
98
+ end
99
+ end
100
+
101
+ def assign_card_list_by_issue
102
+ labels = @origin_issue.labels.map(&:name).uniq
103
+ list = Trellohub.list_by(labels: labels)
104
+ return unless list
105
+ @card_idList = list.id
106
+ @card_list_name = list.name
107
+ end
108
+
109
+ def issue_update?
110
+ !@key.nil?
111
+ end
112
+
113
+ def issue_body
114
+ if @issue_body.nil? && @imported_from == :card
115
+ form = Trellohub::Form.with_issues.find_by_key(@key)
116
+ @issue_body = form.issue_body if form
117
+ end
118
+
119
+ @issue_body
120
+ end
121
+
122
+ def create_issue
123
+ return if @issue_repository.nil? || @issue_title.nil?
124
+
125
+ Octokit.create_issue(
126
+ @issue_repository,
127
+ @issue_title,
128
+ nil,
129
+ to_valid_issue
130
+ )
131
+ end
132
+
133
+ def update_issue
134
+ return if @issue_repository.nil? || @issue_number.nil? || @issue_title.nil?
135
+
136
+ Octokit.update_issue(
137
+ @issue_repository,
138
+ @issue_number,
139
+ @issue_title,
140
+ issue_body,
141
+ to_valid_issue
142
+ )
143
+ end
144
+
145
+ def close_issue
146
+ return if @issue_repository.nil? || @issue_number.nil?
147
+
148
+ Octokit.close_issue(
149
+ @issue_repository,
150
+ @issue_number,
151
+ to_valid_issue
152
+ )
153
+ end
154
+
155
+ def save_as_issue
156
+ case
157
+ when issue_update? && open? then update_issue
158
+ when issue_update? && closed? then close_issue
159
+ when open? then create_issue
160
+ end
161
+ end
162
+
163
+ def to_valid_issue
164
+ Hash[Trellohub::Form::Issue.valid_attributes.map { |key|
165
+ value = instance_variable_get(:"@issue_#{key}")
166
+
167
+ case
168
+ when @imported_from == :issue && !value.empty?
169
+ valid_label = value.find { |v| Trellohub.issue_labels.include?(v) }
170
+ value = []
171
+ value << valid_label if valid_label
172
+ when @imported_from == :card
173
+ form = Trellohub::Form.with_issues.find_by_key(@key)
174
+ value = form.issue_labels if form
175
+ end if key == :labels
176
+
177
+ [key, value]
178
+ }]
179
+ end
180
+
181
+ def to_issue
182
+ Hash[Trellohub::Form::Issue.accessible_attributes.map { |key|
183
+ [
184
+ key.to_s.gsub('issue_', '').to_sym,
185
+ instance_variable_get(:"@#{key}")
186
+ ]
187
+ }]
188
+ end
189
+ end
190
+ end
191
+ end