trello-list2card 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +3 -0
- data/LICENSE +7 -0
- data/README.md +97 -0
- data/bin/list2card +57 -0
- data/etc/config.toml.example +23 -0
- data/etc/test.toml +4 -0
- data/lib/trello/list2card.rb +175 -0
- data/lib/trello/list2card/version.rb +5 -0
- data/trello-list2card.gemspec +24 -0
- metadata +84 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e8f227d65221b15768e81e4effc5a79d23b820ca
|
4
|
+
data.tar.gz: 60aae730bd906d9a83d36da13cd9060c796aa336
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b3657c944296494a992ee16e81c48951baa610a7a772c800b61f2b61b6feaa01488c99b7993d7d37140b621decceaee02a5c03068288367acfb5139eafbd1185
|
7
|
+
data.tar.gz: 96f62bfec4bfaab516fc19885959f802ae4d827b8b6c8a8d64dcd605ba3f7468e7b8999bdd1438d609e644ed7c808ece65d69b59f4ea673b19063f1a66e81569
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/Gemfile.lock
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright 2016 Tom Clark
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# list2card
|
2
|
+
A simple program to summarise the cards on a Trello list as a comment on a card, then archive the cards on the source list.
|
3
|
+
|
4
|
+
## Purpose
|
5
|
+
At the end of every week I summarise the "Done" column of my personal
|
6
|
+
Trello board into a "Captain's Log"
|
7
|
+
metacard, before archiving all of the completed tasks. I wrote `list2card` to automate this process.
|
8
|
+
|
9
|
+
Note: scheduling the execution of `list2card` is left as an exercise for the reader.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
```
|
13
|
+
$ gem install trello-list2card
|
14
|
+
```
|
15
|
+
|
16
|
+
## Configuration
|
17
|
+
`list2card` requires a configuration file to operate. An example is available on [Github](https://github.com/tomonocle/trello-list2card/blob/master/etc/config.toml.example), or you can follow the guide below.
|
18
|
+
|
19
|
+
### Trello API key and token
|
20
|
+
Visit [https://trello.com/app-key](https://trello.com/app-key) to get your unique API key and token.
|
21
|
+
|
22
|
+
Config file:
|
23
|
+
|
24
|
+
```
|
25
|
+
$ cat config.toml
|
26
|
+
user_key = '<KEY>'
|
27
|
+
user_token = '<TOKEN>'
|
28
|
+
```
|
29
|
+
|
30
|
+
### Source list, destination card
|
31
|
+
|
32
|
+
First list your boards to find the id of board you want to work with
|
33
|
+
|
34
|
+
```
|
35
|
+
$ list2card --list-boards
|
36
|
+
* id name url
|
37
|
+
[*] abc123abc123abc123abc123 Test board A https://trello.com/b/abc123ab/test-board-a
|
38
|
+
[ ] 123abc123abc123abc123abc Test board B https://trello.com/b/123abc12/test-board-b
|
39
|
+
```
|
40
|
+
|
41
|
+
Now list the lists on the board to find your `source_list_id`
|
42
|
+
|
43
|
+
```
|
44
|
+
$ list2card --list-lists abc123abc123abc123abc123
|
45
|
+
id name
|
46
|
+
xyz789zxy789xyz789xyz789 Todo
|
47
|
+
789xyz789xyz789xyz789xyz Done
|
48
|
+
```
|
49
|
+
|
50
|
+
Finally list the cards on the appropriate list to find the id of your summary metacard `dest_card_id`
|
51
|
+
|
52
|
+
```
|
53
|
+
$ list2card --list-cards xyz789zxy789xyz789xyz789
|
54
|
+
id name url
|
55
|
+
def456def456def456def456 Captain's Log https://trello.com/c/aabbccdd
|
56
|
+
```
|
57
|
+
|
58
|
+
### Final config file
|
59
|
+
```
|
60
|
+
$ cat config.toml
|
61
|
+
user_key = '<KEY>'
|
62
|
+
user_token = '<TOKEN>'
|
63
|
+
|
64
|
+
source_list_id = '789xyz789xyz789xyz789xyz'
|
65
|
+
dest_card_id = 'def456def456def456def456'
|
66
|
+
```
|
67
|
+
|
68
|
+
## Usage
|
69
|
+
|
70
|
+
```
|
71
|
+
$ list2card -c config.toml
|
72
|
+
```
|
73
|
+
|
74
|
+
This will silently summarise the contents of `source_list_id` into `dest_card_id` as a comment in the following format:
|
75
|
+
|
76
|
+
```
|
77
|
+
N tasks completed
|
78
|
+
<Task 1>
|
79
|
+
<Task ..>
|
80
|
+
<Task N>
|
81
|
+
```
|
82
|
+
|
83
|
+
Before archiving the cards on `source_list_id`.
|
84
|
+
|
85
|
+
Note: No entry will be written if there are no cards to summarise.
|
86
|
+
|
87
|
+
### Logging
|
88
|
+
Log level can be adjusted with `-l [debug,info,warn,error,fatal]` (defaults to **warn**).
|
89
|
+
|
90
|
+
### Dry-run
|
91
|
+
Dry-run (read-only, don't write comment or archive cards) can be enabled with `-d`. Note: you'll probably want to increase the log level with `-l` for this to be useful.
|
92
|
+
|
93
|
+
### Exit codes
|
94
|
+
| Code | Meaning |
|
95
|
+
|:----:|---------|
|
96
|
+
| 0 | Success (wrote output, or nothing to do) |
|
97
|
+
| 1 | Failure. Something went wrong. Always accompanied by a FATAL log message. |
|
data/bin/list2card
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'trello/list2card'
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.banner = 'Usage: list2card -c <config> [options]'
|
8
|
+
|
9
|
+
opts.on( '-c', '--config <config>', 'Path to config file' ) {
|
10
|
+
|c|
|
11
|
+
options[ :config ] = c
|
12
|
+
}
|
13
|
+
|
14
|
+
opts.on( '-l', '--log-level <level>', 'Specify log level (debug,info,warn,error,fatal)' ) {
|
15
|
+
|l|
|
16
|
+
options[ :log_level ] = l
|
17
|
+
}
|
18
|
+
|
19
|
+
opts.on( '-d', '--dry-run', 'Dry run - don\'t change anything' ) {
|
20
|
+
options[ :dry_run ] = true
|
21
|
+
}
|
22
|
+
|
23
|
+
opts.on( '--list-boards', 'Enumerate all boards the user can access' ) {
|
24
|
+
options[ :list_boards ] = true
|
25
|
+
}
|
26
|
+
|
27
|
+
opts.on( '--list-lists <board>', 'Enumerate the lists under <board>' ) {
|
28
|
+
|b|
|
29
|
+
options[ :list_lists ] = b
|
30
|
+
}
|
31
|
+
|
32
|
+
opts.on( '--list-cards <list>', 'Enumerate the cards under <list>' ) {
|
33
|
+
|l|
|
34
|
+
options[ :list_cards ] = l
|
35
|
+
}
|
36
|
+
|
37
|
+
opts.on_tail( '-h', '--help', 'Display help' ) {
|
38
|
+
puts opts
|
39
|
+
exit
|
40
|
+
}
|
41
|
+
end.parse!
|
42
|
+
|
43
|
+
list2card = Trello::List2Card.new( options[ :config ], options[ :log_level ], options[ :dry_run ] )
|
44
|
+
|
45
|
+
## dispatch/routing
|
46
|
+
if ( options[ :list_boards ] )
|
47
|
+
list2card.do_listboards
|
48
|
+
|
49
|
+
elsif ( options[ :list_lists ] )
|
50
|
+
list2card.do_listlists( options[ :list_lists ] )
|
51
|
+
|
52
|
+
elsif ( options[ :list_cards ] )
|
53
|
+
list2card.do_listcards( options[ :list_cards ] )
|
54
|
+
|
55
|
+
else
|
56
|
+
list2card.do_run
|
57
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# log_level
|
2
|
+
# The log_level to operate at: debug/info/warn/error/fatal
|
3
|
+
# log_level = 'warn'
|
4
|
+
|
5
|
+
# user_key
|
6
|
+
# Your trello API key, available at https://trello.com/app-key
|
7
|
+
# e.g user_key = '1234567a12abcd1ab12a123456a1a1a1'
|
8
|
+
user_key = ''
|
9
|
+
|
10
|
+
# user_token
|
11
|
+
# Your trello API token, available at https://trello.com/app-key
|
12
|
+
# e.g user_token = '12a12a1a1ab1ab12ab1234567a1a12345a12abc12a1ab12a123ab1a1ab123a12'
|
13
|
+
user_token = ''
|
14
|
+
|
15
|
+
# source_list_id
|
16
|
+
# The trello id of the list to summarise, available via '--list-lists <board>'
|
17
|
+
# e.g source_list_id = '12a12345678901a1234ab123'
|
18
|
+
source_list_id = ''
|
19
|
+
|
20
|
+
# dest_card_id
|
21
|
+
# The trello id of the card to write the summary to, available via '--list-cards <list>'
|
22
|
+
# e.g dest_card_id = '12a12345678901a1234ab123'
|
23
|
+
dest_card_id = ''
|
data/etc/test.toml
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
module Trello
|
2
|
+
class List2Card
|
3
|
+
require 'logger'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'toml'
|
6
|
+
require 'trello'
|
7
|
+
|
8
|
+
@@LOG_LEVEL_MAP = {
|
9
|
+
'debug' => Logger::DEBUG,
|
10
|
+
'info' => Logger::INFO,
|
11
|
+
'warn' => Logger::WARN,
|
12
|
+
'error' => Logger::ERROR,
|
13
|
+
'fatal' => Logger::FATAL,
|
14
|
+
}
|
15
|
+
|
16
|
+
@@DEFAULT_LOG_LEVEL = 'warn'
|
17
|
+
|
18
|
+
def initialize( config_path, log_level, dry_run )
|
19
|
+
@log = Logger.new( STDERR )
|
20
|
+
self.set_log_level( @@DEFAULT_LOG_LEVEL )
|
21
|
+
|
22
|
+
@log.info 'Starting up'
|
23
|
+
|
24
|
+
begin
|
25
|
+
raise 'config file not specified' if not config_path
|
26
|
+
|
27
|
+
@log.info "Loading config from #{ config_path }"
|
28
|
+
@config = OpenStruct.new( TOML.load_file( config_path ) )
|
29
|
+
@log.info 'Loaded config'
|
30
|
+
@log.debug @config.to_s
|
31
|
+
|
32
|
+
rescue => e
|
33
|
+
@log.fatal "Failed to load config: #{e.message}"
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
|
37
|
+
self.set_log_level( @config[ 'log_level' ] )
|
38
|
+
self.set_log_level( log_level )
|
39
|
+
|
40
|
+
# very basic sanity check of the config
|
41
|
+
[ 'user_key', 'user_token' ].each do |key|
|
42
|
+
if ( not @config[ key ] )
|
43
|
+
@log.fatal "Key #{ key } not present in config"
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Trello.configure do |c|
|
49
|
+
c.developer_public_key = @config.user_key
|
50
|
+
c.member_token = @config.user_token
|
51
|
+
end
|
52
|
+
|
53
|
+
if ( dry_run )
|
54
|
+
@log.warn 'Dry run mode: ON'
|
55
|
+
@dry_run = true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_log_level( level )
|
60
|
+
return if not level
|
61
|
+
|
62
|
+
level.downcase!
|
63
|
+
|
64
|
+
if ( not @@LOG_LEVEL_MAP[ level ] )
|
65
|
+
@log.fatal "Unrecognised log_level '#{ level }'"
|
66
|
+
exit 1
|
67
|
+
end
|
68
|
+
|
69
|
+
@log.level = @@LOG_LEVEL_MAP[ level ]
|
70
|
+
end
|
71
|
+
|
72
|
+
def do_listboards
|
73
|
+
begin
|
74
|
+
me = Trello::Member.find( 'me' )
|
75
|
+
rescue => e
|
76
|
+
@log.fatal "Failed to load boards: #{ e.message }"
|
77
|
+
exit 1
|
78
|
+
end
|
79
|
+
|
80
|
+
puts sprintf ' * %-24s %-42s %s', 'id', 'name', 'url'
|
81
|
+
me.boards( :filter => :open ).each do |board|
|
82
|
+
puts sprintf '[%s] %s %-42s %s', ( board.starred == true ? '*' : ' ' ), board.id, board.name[ 0, 42 ], board.url
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def do_listlists( board_id )
|
87
|
+
begin
|
88
|
+
board = Trello::Board.find( board_id )
|
89
|
+
rescue => e
|
90
|
+
@log.fatal "Failed to load board: #{ e.message }"
|
91
|
+
exit 1
|
92
|
+
end
|
93
|
+
|
94
|
+
puts sprintf '%-24s %s', 'id', 'name'
|
95
|
+
board.lists.each do |list|
|
96
|
+
puts "#{ list.id } #{ list.name }"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def do_listcards( list_id )
|
101
|
+
begin
|
102
|
+
list = Trello::List.find( list_id )
|
103
|
+
rescue => e
|
104
|
+
@log.fatal "Failed to load list: #{ e.message }"
|
105
|
+
exit 1
|
106
|
+
end
|
107
|
+
|
108
|
+
puts sprintf '%-24s %-42s %s', 'id', 'name', 'url'
|
109
|
+
list.cards.each do |card|
|
110
|
+
puts sprintf '%s %-42s %s', card.id, card.name[ 0, 42 ], card.short_url
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def do_run
|
115
|
+
[ 'source_list_id', 'dest_card_id' ].each do |k|
|
116
|
+
if ( not @config[ k ] )
|
117
|
+
@log.fatal "Key #{ k } not present in config"
|
118
|
+
exit 1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# avoid a possible race condition by taking a snapshot of the list
|
123
|
+
source_cards = []
|
124
|
+
|
125
|
+
begin
|
126
|
+
list = Trello::List.find( @config.source_list_id )
|
127
|
+
source_cards = list.cards
|
128
|
+
@log.info "Loaded list #{ @config.source_list_id }"
|
129
|
+
|
130
|
+
rescue => e
|
131
|
+
@log.fatal "Couldn't load list_id '#{ @config.source_list_id }': #{ e.message }"
|
132
|
+
exit 1
|
133
|
+
end
|
134
|
+
|
135
|
+
if ( source_cards.count == 0 ) then
|
136
|
+
@log.info 'No cards to process - aborting'
|
137
|
+
exit 0
|
138
|
+
|
139
|
+
else
|
140
|
+
@log.info "#{ source_cards.count } card(s) to process"
|
141
|
+
end
|
142
|
+
|
143
|
+
# prepare the message itself
|
144
|
+
message = sprintf "%d task%s completed\n\n%s", source_cards.count, ( source_cards.count == 1 ? '' : 's' ), ( source_cards.map { |card| card.short_url } ).join( "\n" )
|
145
|
+
@log.debug "message: '#{ message }'"
|
146
|
+
|
147
|
+
begin
|
148
|
+
log_card = Trello::Card.find( @config.dest_card_id )
|
149
|
+
log_card.add_comment( message ) if not @dry_run
|
150
|
+
@log.info sprintf "%sWrote message to log_card '%s'", ( @dry_run == true ? "[DRYRUN] " : '' ), @config.dest_card_id
|
151
|
+
|
152
|
+
rescue => e
|
153
|
+
@log.fatal "Failed to write message to log_card '#{ config.dest_card_id }': #{ e.message }"
|
154
|
+
exit 1
|
155
|
+
end
|
156
|
+
|
157
|
+
# Successfully posted the message, now archive the cards
|
158
|
+
source_cards.each do |card|
|
159
|
+
begin
|
160
|
+
if ( not @dry_run )
|
161
|
+
card.close
|
162
|
+
card.save
|
163
|
+
end
|
164
|
+
|
165
|
+
@log.info sprintf "%sArchived '%s' (%s)", ( @dry_run == true ? '[DRYRUN] ' : '' ), card.name, card.id
|
166
|
+
|
167
|
+
rescue => e
|
168
|
+
@log.error "Failed to archive '#{ card.id }'"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
@log.info 'Done'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'trello/list2card/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'trello-list2card'
|
8
|
+
spec.version = Trello::List2Card::VERSION
|
9
|
+
spec.author = 'tomonocle'
|
10
|
+
spec.email = 'tomonocle@woot.co.uk'
|
11
|
+
spec.license = 'MIT'
|
12
|
+
|
13
|
+
spec.summary = 'Tool to summarise a Trello list to a card'
|
14
|
+
spec.description = 'A simple program to summarise the cards on a Trello list as a comment on a card, then archive the cards on the source list.'
|
15
|
+
spec.homepage = 'https://github.com/tomonocle/trello-list2card'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = 'bin'
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_dependency 'ruby-trello', '~> 1.5'
|
23
|
+
spec.add_dependency 'toml-rb', '~> 0.3'
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trello-list2card
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- tomonocle
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-trello
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: toml-rb
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.3'
|
41
|
+
description: A simple program to summarise the cards on a Trello list as a comment
|
42
|
+
on a card, then archive the cards on the source list.
|
43
|
+
email: tomonocle@woot.co.uk
|
44
|
+
executables:
|
45
|
+
- list2card
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- CHANGELOG.md
|
51
|
+
- Gemfile
|
52
|
+
- LICENSE
|
53
|
+
- README.md
|
54
|
+
- bin/list2card
|
55
|
+
- etc/config.toml.example
|
56
|
+
- etc/test.toml
|
57
|
+
- lib/trello/list2card.rb
|
58
|
+
- lib/trello/list2card/version.rb
|
59
|
+
- trello-list2card.gemspec
|
60
|
+
homepage: https://github.com/tomonocle/trello-list2card
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 2.4.5
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: Tool to summarise a Trello list to a card
|
84
|
+
test_files: []
|