ytrello 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 65edc7ba791b0cd9457ea8335c2da006cb63dd3b
4
+ data.tar.gz: 280867290171ee8c6d67807578bfd8498810fa4c
5
+ SHA512:
6
+ metadata.gz: f0655da07f7cda5f7132f465ec12551e37817dab3e63ea7912e5b1340c65440cb7f14f9a12e0c20c6c1c4f2cfa5cb86319f610e06d1614ed3201df4a7d50e486
7
+ data.tar.gz: eb3569f6e2cce36f0992070beb70dfa0a26c4f1f3336d22602670c00869cca702db4ca39062fca93eee2bb12082911bf8bb380ad63d73303bdc798dcf2db145b
@@ -0,0 +1,7 @@
1
+ /.bundle/
2
+ /vendor/
3
+ /.vendor/
4
+ oscrc
5
+ trello-creds.yml
6
+ ytrello-*.gem
7
+ Gemfile.lock
@@ -0,0 +1,104 @@
1
+ # NOTE: This is a copy from https://github.com/yast/yast-devtools/blob/master/ytools/y2tool/rubocop_yast_style.yml
2
+
3
+ ################################################################################
4
+ #
5
+ # This part contains the shared Rubocop configuration for SUSE projects. It is
6
+ # maintained at https://github.com/SUSE/style-guides/blob/master/rubocop-suse.yml
7
+ #
8
+ # NOTE: some rules have been commented out, see the YaST specific changes
9
+ # at the end of the file!
10
+ #
11
+ ################################################################################
12
+
13
+ # Disabled, would require too many changes in the current code
14
+ #Lint/EndAlignment:
15
+ # StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#lintendalignment
16
+ # AlignWith: variable
17
+
18
+ Metrics/AbcSize:
19
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#metricsabcsize
20
+ Max: 30
21
+
22
+ Metrics/LineLength:
23
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#metricslinelength
24
+ Max: 100
25
+ # To make it possible to copy or click on URIs in the code, we allow lines
26
+ # contaning a URI to be longer than Max.
27
+ AllowURI: true
28
+ URISchemes:
29
+ - http
30
+ - https
31
+
32
+ Style/AlignHash:
33
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#stylealignhash
34
+ EnforcedHashRocketStyle: table
35
+ EnforcedColonStyle: table
36
+
37
+ # Disabled, see the YaST default at the end of the file
38
+ #Style/AlignParameters:
39
+ # StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#stylealignparameters
40
+ # Enabled: false
41
+
42
+ Style/CollectionMethods:
43
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#stylecollectionmethods
44
+ Enabled: false
45
+
46
+ Style/EmptyLinesAroundBlockBody:
47
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#styleemptylinesaroundblockbody
48
+ Enabled: false
49
+
50
+ Style/MultilineOperationIndentation:
51
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#stylemultilineoperationindentation
52
+ EnforcedStyle: indented
53
+
54
+ Style/StringLiterals:
55
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#stylestringliterals
56
+ EnforcedStyle: double_quotes
57
+
58
+ Style/StringLiteralsInInterpolation:
59
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#stylestringliteralsininterpolation
60
+ EnforcedStyle: double_quotes
61
+
62
+ Style/WordArray:
63
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#deviations-from-the-upstream-style-guide
64
+ Enabled: false
65
+
66
+ Style/RegexpLiteral:
67
+ StyleGuide: https://github.com/SUSE/style-guides/blob/master/Ruby.md#deviations-from-the-upstream-style-guide
68
+ Enabled: false
69
+
70
+ Style/SignalException:
71
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#fail-method
72
+ EnforcedStyle: only_raise
73
+
74
+
75
+ ################################################################################
76
+ #
77
+ # This part contains the YaST specific changes to the shared SUSE configuration
78
+ #
79
+ ################################################################################
80
+
81
+ # no extra indentation for multiline function calls
82
+ Style/AlignParameters:
83
+ EnforcedStyle: with_fixed_indentation
84
+
85
+ # no extra indentation for case
86
+ Style/CaseIndentation:
87
+ IndentWhenRelativeTo: end
88
+
89
+ # "unless" has a different connotation than "if not"
90
+ Style/NegatedIf:
91
+ Enabled: false
92
+
93
+ # allow more than 10 lines for methods
94
+ Metrics/MethodLength:
95
+ Max: 30
96
+
97
+ Metrics/ClassLength:
98
+ Max: 250
99
+
100
+ AllCops:
101
+ # do not check the locally installed gems
102
+ Exclude:
103
+ - '.vendor/**/*'
104
+ - 'vendor/**/*'
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ sudo: false
3
+ rvm:
4
+ # openSUSE Leap 15, SLE 15
5
+ - 2.5.0
6
+ # openSUSE Leap 42.3
7
+ - 2.4.1
8
+ script:
9
+ - bundle exec rubocop
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
@@ -0,0 +1,117 @@
1
+ # YTrello
2
+
3
+ Tools to help with the YaST Trello boards.
4
+
5
+ - Make cards for bugs in Bugzilla.suse.com
6
+
7
+ ### Requirements
8
+
9
+ - [bicho.gem][b] >= 0.0.10
10
+ - [ruby-trello.gem][t]
11
+ - [python-bugzilla][p], with the SUSE flavor
12
+
13
+ [b]: https://github.com/dmacvicar/bicho
14
+ [t]: https://github.com/jeremytregunna/ruby-trello
15
+ [p]: https://build.opensuse.org/package/show/openSUSE:Factory/python-bugzilla
16
+
17
+ ### Installation
18
+
19
+ From a Git checkout:
20
+
21
+ ```sh
22
+ sudo zypper install python-bugzilla
23
+ bundle install
24
+ alias ytrello="bundle exec ytrello"
25
+ ```
26
+
27
+ From Rubygems:
28
+
29
+ ```sh
30
+ sudo zypper install python-bugzilla
31
+ gem install ytrello
32
+ ```
33
+
34
+ From OBS (TODO, does not exist yet!), this selects the appropriate Ruby version:
35
+
36
+ ```sh
37
+ zypper install -C 'rubygem(ytrello)'
38
+ ```
39
+
40
+ ### Setup
41
+
42
+ **ruby-trello** reads the configuration file `~/.config/trello-creds.yml`:
43
+
44
+ - The Developer Public Key is the first hex string on
45
+ <https://trello.com/app-key>
46
+
47
+ ```sh
48
+ F=~/.config/trello-creds.yml`
49
+ touch $F
50
+ chmod 700 $F
51
+ echo "# https://github.com/mvidner/ytrello" >> $F
52
+ echo "TRELLO_DEVELOPER_PUBLIC_KEY: replaceme" >> $F
53
+ vi $F
54
+ ```
55
+
56
+ After you fill in the developer key, use this to request an app token, then
57
+ copy the generated token to the config file.
58
+
59
+ ```sh
60
+ xdg-open "https://trello.com/1/authorize?key=REPLACEME&name=ytrello&expiration=never&response_type=token&scope=read,write"
61
+ echo "TRELLO_MEMBER_TOKEN: replaceme" >>$F
62
+ vi $F
63
+ ```
64
+
65
+ For backward compatibility, the environment variables
66
+ `TRELLO_DEVELOPER_PUBLIC_KEY` and `TRELLO_MEMBER_TOKEN` are respected, and
67
+ even preferred over the configuration file.
68
+
69
+ **bicho** and **python-bugzilla** read ~/.oscrc so if you have used `osc` it
70
+ should work already.
71
+
72
+ ## Usage
73
+
74
+ - **create**
75
+
76
+ ```sh
77
+ ytrello create $BUG_NUMBER
78
+ ```
79
+
80
+
81
+ - **addurl** is normally called by **create**,
82
+ but in case you want to use it directly, it is straightforward. It will
83
+ assign the **URL** field of a bug unless the field is already present.
84
+
85
+ ```sh
86
+ ytrello addurl 999999 https://trello.example.com/cards/my-first-card
87
+ ```
88
+
89
+ - **check** runs some validation checks and reports the found issues:
90
+
91
+ - It checks whether the YaST team bugs have a link to a Trello card (in the
92
+ **URL** field).
93
+ - It checks that all open YaST team bugs are tracked in Trello (i.e. a card
94
+ exists).
95
+ - Reports the Trello cards which refer to a closed bug in bugzilla. These
96
+ cards should be moved to *Done* or archived if the bug is not valid anymore.
97
+
98
+ The command supports a simple auto correction mode. In this mode it tries
99
+ to fix the found issues. Use `-a` or `--auto-correct` option to turn it on
100
+ (by default it is disabled).
101
+
102
+ Currently these auto correct actions are performed:
103
+
104
+ - The missing links from Bugzilla bugs to the Trello cards are added.
105
+ - Missing Trello cards are created
106
+
107
+ It is recommended to run it in read-only mode first to see the found issues:
108
+
109
+ ```sh
110
+ ytrello check
111
+ ```
112
+
113
+ If the reported changes are valid you can fix them by running:
114
+
115
+ ```sh
116
+ ytrello check -a
117
+ ```
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.18.0
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ subcommand = ARGV.shift
4
+
5
+ if subcommand.nil?
6
+ puts "Usage: ytrello SUBCOMMAND [ARGUMENTS...]"
7
+ exit 1
8
+ end
9
+
10
+ system "ytrello-#{subcommand}", *ARGV
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # Add a [related] URL field to a bug
3
+ bug_num = ARGV[0]
4
+ card_url = ARGV[1]
5
+
6
+ has_url = `bugzilla query --outputformat='%{bug_file_loc}' -b #{bug_num}`.chomp
7
+
8
+ if has_url.empty?
9
+ system "bugzilla", "modify", "--url", card_url, bug_num
10
+ puts "Card URL added to Bugzilla"
11
+ end
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env ruby
2
+ require "ytrello"
3
+
4
+ require "rainbow"
5
+ require "optparse"
6
+
7
+ # If a Trello card contains just a number without "FATE" (case insensitive)
8
+ # it might be a FATE number instead of a bug number. Consider it as a possible
9
+ # FATE number if it is below this limit.
10
+ FATE_NUMBER_MAX = 400_000
11
+
12
+ def parse_options
13
+ options = {}
14
+
15
+ op = OptionParser.new do |opts|
16
+ opts.banner =
17
+ "\nThis script checks whether the YaST Trello boards are in sync with the Bugzilla.\n\n" \
18
+ "The Trello credentials are read from the #{ENV_TRELLO_KEY} and #{ENV_TRELLO_TOKEN}\n" \
19
+ "environment variables. The Bugzilla credentials are read from the '~/.oscrc' file.\n\n" \
20
+ "Usage: #{$PROGRAM_NAME} [options]\n\n"
21
+
22
+ opts.on("-a", "--auto-correct", "Try to fix the detected problems, " \
23
+ "currently only the missing Trello cards are created") do
24
+
25
+ options[:auto_correct] = true
26
+ end
27
+
28
+ opts.on("-h", "--help", "Print this help") do
29
+ puts opts
30
+ exit 0
31
+ end
32
+ end
33
+
34
+ op.parse!
35
+
36
+ options
37
+ end
38
+
39
+ # query the bugs assigned to the YaST Team
40
+ # @return [Hash<Symbol,Array<BichoBug>>] :all => all team bugs, :missing =>
41
+ # bugs with empty URL attribute, :unknown => the URL is set, but does not
42
+ # point to a Trello URL
43
+ def check_team_bugs
44
+ missing_bugs = []
45
+ unknown_links = []
46
+
47
+ # ignore closed bugs
48
+ all_bugs = Bicho::Bug.where(assigned_to: BUGZILLA_ACCOUNT).select do |bug|
49
+ bug.resolution.empty?
50
+ end
51
+
52
+ all_bugs.each do |bug|
53
+ if bug["url"].nil? || bug["url"].empty?
54
+ missing_bugs << bug
55
+ elsif !bug["url"].include?("https://trello.com/")
56
+ unknown_links << bug
57
+ end
58
+ end
59
+
60
+ { all: all_bugs, missing: missing_bugs, unknown: unknown_links }
61
+ end
62
+
63
+ # read all Trello cards from the Incoming and the Team boards
64
+ # @return [Array<Trello::Card>] found cards
65
+ def trello_cards
66
+ inc_board = Trello::Board.find(INC_BOARD_ID) || raise
67
+ t1_board = Trello::Board.find(TEAM_1_BOARD_ID) || raise
68
+ ta_board = Trello::Board.find(TEAM_A_BOARD_ID) || raise
69
+
70
+ to_array(inc_board.cards) + to_array(t1_board.cards) + to_array(ta_board.cards)
71
+ end
72
+
73
+ # @return [Hash<Fixnum,Trello::Card>] map bug ID => Trello card
74
+ def find_trello_bugs
75
+ trello_bugs = {}
76
+
77
+ trello_cards.each do |card|
78
+ # skip cards not in the specified list
79
+ next unless CHECKED_LISTS.include?(card.list_id)
80
+
81
+ # TODO: skip FATE cards for now, maybe add a FATE check as well?
82
+ next if card.name.match(/\bfate\b/i) || card.name.match(/\bfeature\b/i)
83
+
84
+ # skip cards not containing any bug number
85
+ # expect bug numbers have 6 or 7 digits
86
+ next unless card.name =~ /\b#?(\d{6,7})\b/
87
+
88
+ bug_id = Regexp.last_match[1].to_i
89
+ trello_bugs[bug_id] = card
90
+ end
91
+
92
+ trello_bugs
93
+ end
94
+
95
+ def find_closed_trello_bugs(found_trello_bugs)
96
+ closed_bugs = {}
97
+ # ignore "small" numbers, they most probably refer to a feature
98
+ bugnumbers = found_trello_bugs.keys.select { |n| n > FATE_NUMBER_MAX }
99
+
100
+ Bicho.client.get_bugs(*bugnumbers).each do |bug|
101
+ next if bug.resolution.empty?
102
+ closed_bugs[bug] = found_trello_bugs[bug.id]
103
+ end
104
+
105
+ closed_bugs
106
+ end
107
+
108
+ def print_bugzilla_summary(team_bugs)
109
+ team_bugs[:missing].each do |bug|
110
+ puts "Bug #{Rainbow(bug.url).yellow}: URL attribute not set"
111
+ end
112
+
113
+ team_bugs[:unknown].each do |bug|
114
+ puts "Bug #{Rainbow(bug.url).yellow}: URL \"#{bug["url"]}\"does not link to Trello "
115
+ end
116
+ end
117
+
118
+ # check if a number in Trello card label possibly refers to FATE instead of bugzilla
119
+ def print_trello_fate_warnings(open_trello_bugs)
120
+ open_trello_bugs.each do |bug_id, card|
121
+ # enough high number or "bug" in the name
122
+ next if bug_id > FATE_NUMBER_MAX || card.name.match(/\bbug\b/i)
123
+
124
+ puts "#{Rainbow(card.short_url).yellow} - " \
125
+ "#{card.name.sub(bug_id.to_s, Rainbow(bug_id.to_s).magenta)}"
126
+ puts "Number #{Rainbow(bug_id).magenta} possibly refers to " \
127
+ "FATE, add \"FATE\" string if it is a feature number"
128
+ puts
129
+ end
130
+ end
131
+
132
+ def print_trello_closed_bugs(trello_closed_bugs)
133
+ trello_closed_bugs.each do |bug, card|
134
+ puts Rainbow(card.name).cyan
135
+ puts "#{Rainbow(card.short_url).yellow} refers to #{Rainbow(bug.url).yellow}" \
136
+ " resolved as #{Rainbow(bug.resolution).red}"
137
+ puts
138
+ end
139
+ end
140
+
141
+ def print_summary_line(line, ok)
142
+ puts Rainbow(line).color(ok ? :green : :red)
143
+ end
144
+
145
+ def print_summary(team_bugs, open_trello_bugs, closed_trello_bugs)
146
+ not_in_trello = bugs_not_in_trello(team_bugs, open_trello_bugs)
147
+
148
+ puts
149
+ print_summary_line("Found #{not_in_trello.size} bugs not in Trello", not_in_trello.empty?)
150
+ print_summary_line("Found #{team_bugs[:all].size} YaST Team bugs, " \
151
+ "#{team_bugs[:missing].size} do not link to Trello.", team_bugs[:missing].empty?)
152
+ print_summary_line("Found #{open_trello_bugs.size} bug cards in Trello, " \
153
+ "#{closed_trello_bugs.size} possibly refer to a closed bug.", closed_trello_bugs.empty?)
154
+ puts
155
+ end
156
+
157
+ def bugs_not_in_trello(team_bugs, open_trello_bugs)
158
+ team_bugs[:all].map(&:id) - open_trello_bugs.keys.map(&:to_i)
159
+ end
160
+
161
+ def print_not_in_trello(not_in_trello)
162
+ not_in_trello.each do |bug|
163
+ bug_url = "https://bugzilla.suse.com/#{bug}"
164
+ puts "Bug #{Rainbow(bug_url).yellow} is not tracked in Trello"
165
+ end
166
+ end
167
+
168
+ def print_result(team_bugs, open_trello_bugs, closed_trello_bugs)
169
+ not_in_trello = bugs_not_in_trello(team_bugs, open_trello_bugs)
170
+ print_not_in_trello(not_in_trello)
171
+ print_bugzilla_summary(team_bugs)
172
+ print_trello_fate_warnings(open_trello_bugs)
173
+ print_trello_closed_bugs(closed_trello_bugs)
174
+ print_summary(team_bugs, open_trello_bugs, closed_trello_bugs)
175
+ end
176
+
177
+ ######################################################
178
+
179
+ options = parse_options
180
+
181
+ setup_bicho
182
+ setup_trello
183
+
184
+ puts "Reading the bugs assigned to #{BUGZILLA_ACCOUNT}..."
185
+ team_bugs = check_team_bugs
186
+
187
+ puts "Reading the YaST Trello cards..."
188
+ trello_bugs = find_trello_bugs
189
+
190
+ puts "Reading bugs referred in the YaST Trello cards..."
191
+ closed_trello_bugs = find_closed_trello_bugs(trello_bugs)
192
+ not_in_trello = bugs_not_in_trello(team_bugs, trello_bugs)
193
+
194
+ print_result(team_bugs, trello_bugs, closed_trello_bugs)
195
+
196
+ # no issue found
197
+ exit 0 if team_bugs[:missing].empty? && closed_trello_bugs.empty? && not_in_trello.empty?
198
+
199
+ # try fixing some problems
200
+ if options[:auto_correct]
201
+ puts "Running autocorrection..."
202
+ create_script = File.expand_path("../create", __FILE__)
203
+
204
+ team_bugs[:missing].each do |bug|
205
+ puts "Creating a Trello card for bug ##{bug.id}..."
206
+ `#{create_script} #{bug.id}`
207
+ end
208
+
209
+ not_in_trello.each do |bug|
210
+ puts "Creating a Trello card for bug ##{bug}..."
211
+ `#{create_script} #{bug}`
212
+ end
213
+
214
+ # potentially fixed everything?
215
+ exit 0 if closed_trello_bugs.empty?
216
+ end
217
+
218
+ exit 1
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env ruby
2
+ require "ytrello"
3
+ require "English"
4
+
5
+ if ARGV.empty? || ARGV[0].include?("-h")
6
+ puts "Usage: #{$PROGRAM_NAME} bug_number"
7
+ puts " Creates a trello card for a bug, links the bug to the card"
8
+ exit 0
9
+ end
10
+
11
+ setup_trello
12
+ setup_bicho
13
+
14
+ # abbreviate a SUSE product name
15
+ def abbrev(s)
16
+ s
17
+ .sub("openSUSE", "oS")
18
+ .sub("SUSE Linux Enterprise Desktop", "SLED")
19
+ .sub("SUSE Linux Enterprise Server", "SLES")
20
+ .sub("SUSE Container as a Service Platform 1.0", "CaaSP1")
21
+ .sub(/\(.*\)/, "") # remove superfluous abbreviation
22
+ .sub(" SP", "-SP")
23
+ .sub(" Factory", "-TW") # Tumbleweed
24
+ .tr(" ", "")
25
+ end
26
+
27
+ # Trello list IDs, see also show_list_ids
28
+ PRODUCT_LISTS = {
29
+ /SLE[SD]15/ => "5952060e0e9190605c75863e", # SLE 15
30
+ # "59a3db0f0fac7c99d1808ae9" is "SLE 15 Storage" but we can't autodetect that
31
+ /SLE[SD]12-SP3/ => "57cfdbcc9ae10f3d1fb996d3", # SLE-12-SP3 Maintenance
32
+ /SLE[SD]12-SP2/ => "5538994821027776154180eb", # SLE12-SP2 Maintenance
33
+ /SLE[SD]12-SP1/ => "5502d6719b0d5db70bcf6655", # SLE12-SP1 maintenance
34
+ /SLE[SD]12/ => "5507f04f2c885ffbdd53208a", # SLE12-maintenance
35
+ /SLE[SD]11/ => "5507f140ab44b6bcfcc6c561", # SLE11-maintenance
36
+ /^oS/ => "550800984de3079fa9ded12a", # openSUSE
37
+ /CaaSP1/ => "5877cf5650f2787cf6eb25a1", # CaaSP 1.0
38
+ # fallback
39
+ /./ => "5507f28d31c1cfac7a83eb72" # Generic Ideas
40
+ }.freeze
41
+
42
+ def product_to_list(product)
43
+ PRODUCT_LISTS.to_a.each do |pattern, list_id|
44
+ return list_id if product =~ pattern
45
+ end
46
+ raise "Internal error, PRODUCT_LISTS did not match"
47
+ end
48
+
49
+ def markdown_link(text, url)
50
+ "[#{text}](#{url})"
51
+ end
52
+
53
+ def bz_markdown_link(id)
54
+ markdown_link("bsc##{id}", "#{BUGZILLA_URL}/show_bug.cgi?id=#{id}")
55
+ end
56
+
57
+ def bicho_details(bug_id)
58
+ bug = Bicho.client.get_bugs(bug_id).first
59
+ raise "Bug ##{bug_id} not found" unless bug
60
+ bug.priority =~ /^(\S+)\s/
61
+ { summary: bug.summary, product: bug.product, priority: Regexp.last_match(1) }
62
+ end
63
+
64
+ # create a card description text
65
+ # @param bug_id bug number
66
+ # @return [String] description text in the Markdown format
67
+ def card_description(bug_id)
68
+ descr = <<EOT
69
+ Bugzilla: #{bz_markdown_link(bug_id)}
70
+
71
+ ---
72
+ ## Review
73
+ - Pull Request: *URL here*
74
+ EOT
75
+
76
+ # just to avoid the trailing blank errors in the heredoc
77
+ descr + "- "
78
+ end
79
+
80
+ bug_id = ARGV[0]
81
+ details = bicho_details(bug_id)
82
+ product = abbrev(details[:product])
83
+ card_name = "#{product} (#{details[:priority]}) ##{bug_id} #{details[:summary]}"
84
+ description = card_description(bug_id)
85
+ list_id = product_to_list(product)
86
+ # list_id = "546336636415e12617f88e47" # My work / Done
87
+
88
+ debug "Trello query"
89
+ inc_board = Trello::Board.find(INC_BOARD_ID) || raise
90
+ t1_board = Trello::Board.find(TEAM_1_BOARD_ID) || raise
91
+ ta_board = Trello::Board.find(TEAM_A_BOARD_ID) || raise
92
+
93
+ labels = inc_board.labels(false) # false: objects; true: names
94
+ new_item_label = labels.find { |i| i.name =~ /new.item/i } || raise
95
+
96
+ list = Trello::List.find(list_id) ||
97
+ raise("Cannot find list #{list_id} to represent #{details[:product]}")
98
+
99
+ inc_cards = to_array inc_board.cards
100
+ t1_cards = to_array t1_board.cards
101
+ ta_cards = to_array ta_board.cards
102
+
103
+ existing = (inc_cards + t1_cards + ta_cards).find_all do |c|
104
+ c.name =~ /\D#{bug_id}\D/
105
+ end
106
+
107
+ card = nil
108
+ if existing.empty?
109
+ debug "Creating"
110
+
111
+ raise "Trying to add to already archived list '#{list.name}'" if list.closed
112
+
113
+ card = Trello::Card.create(list_id: list_id,
114
+ name: card_name,
115
+ desc: description,
116
+ pos: "top")
117
+ card.add_label(new_item_label)
118
+ puts "Created #{bug_id} => #{card.short_url}"
119
+ else
120
+ puts "Card for bug already exists:"
121
+ existing.each { |c| puts c.url }
122
+ card = existing.first if existing.size == 1
123
+ end
124
+
125
+ if card
126
+ debug "Assigning card URL in Bugzilla"
127
+ system "ytrello", "addurl", bug_id.to_s, card.short_url.to_s
128
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ bug_num = ARGV[0]
4
+ FROM = "yast2-maintainers@suse.de".freeze
5
+ TO = "yast-internal@suse.de".freeze
6
+
7
+ if bug_num.nil? || bug_num == "-h"
8
+ puts <<TXT
9
+ Usage: ytrello-reassign BUGNUM
10
+
11
+ Reassign a bug
12
+ from the incoming account #{FROM}
13
+ to the scrum account #{TO}
14
+ Does nothing if the original assignee is different.
15
+ TXT
16
+ exit 1
17
+ end
18
+
19
+ assignee = `bugzilla query --outputformat='%{assigned_to}' -b #{bug_num}`
20
+ if assignee == FROM
21
+ puts "Changing assignee from #{assignee} to #{TO}"
22
+ system "bugzilla", "modify", "--assignee", TO, bug_num
23
+ elsif assignee == TO
24
+ puts "Assignee #{assignee} is already correct; unchanged"
25
+ else
26
+ puts "Assignee #{assignee} unchanged"
27
+ end
@@ -0,0 +1,3 @@
1
+ # Put this to ~/.config/trello-creds.yml
2
+ TRELLO_DEVELOPER_PUBLIC_KEY: ffffffffffffffffffffffffffffffff
3
+ TRELLO_MEMBER_TOKEN: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../ytrello"
4
+
5
+ setup_trello
6
+
7
+ inc_board = Trello::Board.find(INC_BOARD_ID) || raise
8
+ inc_board.lists.each { |l| puts "\"#{l.id}\", # #{l.name}" }
@@ -0,0 +1,87 @@
1
+ require "trello"
2
+ require "bicho"
3
+ require "yaml"
4
+
5
+ # Trello board IDs
6
+ INC_BOARD_ID = "5507f013b863aa041618871d".freeze # Agile YaST Incoming Board
7
+ TEAM_1_BOARD_ID = "5502d5dd8eb45fb4581c1a0f".freeze # Agile YaST: Team 1
8
+ TEAM_A_BOARD_ID = "557833ad6be7b9634f089201".freeze # Agile YaST: Team A
9
+
10
+ # Trello list IDs, see also show_list_ids
11
+ CHECKED_LISTS = [
12
+ # Incoming board, keep sorted same as incomming board
13
+ # Backlog Team A
14
+ "5502d691d05c3b3817317566",
15
+ # Backlog Team 1
16
+ "557835b5cb9c13dcd032ecbb",
17
+ # SLE15 development
18
+ "5952060e0e9190605c75863e",
19
+ # SLE15 Storage development
20
+ "59a3db0f0fac7c99d1808ae9",
21
+ # SLE12-SP3 maintenance"
22
+ "57cfdbcc9ae10f3d1fb996d3",
23
+ # SLE12-SP2 development
24
+ "5538994821027776154180eb",
25
+ # Generic Ideas
26
+ "5507f28d31c1cfac7a83eb72",
27
+ # SLE12-maintenance
28
+ "5507f04f2c885ffbdd53208a",
29
+ # SLE12-SP1 maintenance
30
+ "5502d6719b0d5db70bcf6655",
31
+ # SLE11-maintenance
32
+ "5507f140ab44b6bcfcc6c561",
33
+ # openSUSE
34
+ "550800984de3079fa9ded12a",
35
+
36
+ # Team 1 boards
37
+ # Sprint Backlog
38
+ "5577ed07930f16fb224ca248",
39
+ # Doing
40
+ "5502d6b29a7a2ab8025a4c56",
41
+
42
+ # Team A boards
43
+ # Sprint Backlog
44
+ "5502d69d3e68ab3d1729337e",
45
+ # Doing
46
+ "557833dde4f1218b7d1cf831"
47
+ ].freeze
48
+
49
+ BUGZILLA_URL = "https://bugzilla.suse.com".freeze
50
+ BUGZILLA_ACCOUNT = "yast-internal@suse.de".freeze
51
+
52
+ ENV_TRELLO_KEY = "TRELLO_DEVELOPER_PUBLIC_KEY".freeze
53
+ ENV_TRELLO_TOKEN = "TRELLO_MEMBER_TOKEN".freeze
54
+
55
+ # set the SUSE Bugzilla connection
56
+ def setup_bicho
57
+ Bicho.client = Bicho::Client.new(BUGZILLA_URL)
58
+ end
59
+
60
+ # set the Trello credentials
61
+ def setup_trello
62
+ fn = "#{ENV["HOME"]}/.config/trello-creds.yml"
63
+ text = File.exist?(fn) ? File.read(fn) : ""
64
+ creds = Hash(YAML.safe_load(text))
65
+ key = ENV[ENV_TRELLO_KEY] || creds[ENV_TRELLO_KEY]
66
+ token = ENV[ENV_TRELLO_TOKEN] || creds[ENV_TRELLO_TOKEN]
67
+ unless key && token
68
+ msg = "Error: Pass the Trello credentials via #{ENV_TRELLO_KEY} and\n" \
69
+ " #{ENV_TRELLO_TOKEN}, either in #{fn} or in environment variables."
70
+ $stderr.puts msg
71
+ exit 1
72
+ end
73
+
74
+ Trello.configure do |config|
75
+ config.developer_public_key = key
76
+ config.member_token = token
77
+ end
78
+ end
79
+
80
+ # Array#to_a -> Trello::MultiAssociation, WTF?!
81
+ def to_array(a)
82
+ a.map { |i| i }
83
+ end
84
+
85
+ def debug(s)
86
+ $stderr.puts s if $VERBOSE
87
+ end
@@ -0,0 +1,4 @@
1
+ module Ytrello
2
+ # Ytrello version (uses [semantic versioning](http://semver.org/)).
3
+ VERSION = File.read(File.dirname(__FILE__) + "/../../VERSION").strip
4
+ end
@@ -0,0 +1,49 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + "/lib/ytrello/version")
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "ytrello"
7
+ s.version = Ytrello::VERSION
8
+ s.summary = "Tools to help with the YaST Trello boards and Bugzilla"
9
+ s.description = <<TXT
10
+ Ytrello are tools to help my Scrum team manage Trello cards and Bugzilla bugs.
11
+ Much of the configuration is harcoded now, yuck!
12
+ TXT
13
+
14
+ s.author = "Martin Vidner"
15
+ s.email = "martin@vidner.net"
16
+ s.homepage = "https://github.com/mvidner/ytrello"
17
+ s.license = "MIT"
18
+
19
+ # ruby -e 'puts `git ls-files`.lines.map { |f| " %s" % f.strip.inspect }.join ",\n"'
20
+ s.files = [
21
+ ".gitignore",
22
+ ".rubocop.yml",
23
+ ".travis.yml",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "README.md",
27
+ "VERSION",
28
+ "bin/ytrello",
29
+ "bin/ytrello-addurl",
30
+ "bin/ytrello-check",
31
+ "bin/ytrello-create",
32
+ "bin/ytrello-reassign",
33
+ "config/trello-creds.yml.template",
34
+ "devel/show_list_ids",
35
+ "lib/ytrello.rb",
36
+ "lib/ytrello/version.rb",
37
+ "ytrello.gemspec"
38
+ ]
39
+
40
+ s.executables = s.files.grep(/^bin\//) { |f| File.basename(f) }
41
+
42
+ s.requirements << "python-bugzilla, with the SUSE flavor"
43
+
44
+ s.add_dependency "bicho", ">= 0.0.10"
45
+ s.add_dependency "ruby-trello", "~> 1.3.0"
46
+ s.add_dependency "rainbow", ">= 2.0.0"
47
+
48
+ s.add_development_dependency "rubocop", "0.41.2"
49
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ytrello
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.18.0
5
+ platform: ruby
6
+ authors:
7
+ - Martin Vidner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bicho
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.10
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.10
27
+ - !ruby/object:Gem::Dependency
28
+ name: ruby-trello
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rainbow
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.0.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.41.2
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.41.2
69
+ description: |
70
+ Ytrello are tools to help my Scrum team manage Trello cards and Bugzilla bugs.
71
+ Much of the configuration is harcoded now, yuck!
72
+ email: martin@vidner.net
73
+ executables:
74
+ - ytrello
75
+ - ytrello-addurl
76
+ - ytrello-check
77
+ - ytrello-create
78
+ - ytrello-reassign
79
+ extensions: []
80
+ extra_rdoc_files: []
81
+ files:
82
+ - ".gitignore"
83
+ - ".rubocop.yml"
84
+ - ".travis.yml"
85
+ - Gemfile
86
+ - Gemfile.lock
87
+ - README.md
88
+ - VERSION
89
+ - bin/ytrello
90
+ - bin/ytrello-addurl
91
+ - bin/ytrello-check
92
+ - bin/ytrello-create
93
+ - bin/ytrello-reassign
94
+ - config/trello-creds.yml.template
95
+ - devel/show_list_ids
96
+ - lib/ytrello.rb
97
+ - lib/ytrello/version.rb
98
+ - ytrello.gemspec
99
+ homepage: https://github.com/mvidner/ytrello
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements:
118
+ - python-bugzilla, with the SUSE flavor
119
+ rubyforge_project:
120
+ rubygems_version: 2.2.5
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: Tools to help with the YaST Trello boards and Bugzilla
124
+ test_files: []