trellohub 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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