ytrello 0.18.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,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: []