trello_flow 1.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +24 -0
- data/Rakefile +10 -0
- data/exe/git-cleanup +7 -0
- data/exe/git-finish +7 -0
- data/exe/git-open +7 -0
- data/exe/git-start +7 -0
- data/lib/trello_flow/api/base.rb +29 -0
- data/lib/trello_flow/api/card.rb +28 -0
- data/lib/trello_flow/api/checklist.rb +38 -0
- data/lib/trello_flow/api/item.rb +70 -0
- data/lib/trello_flow/api/json_parser.rb +13 -0
- data/lib/trello_flow/api/member.rb +9 -0
- data/lib/trello_flow/branch.rb +66 -0
- data/lib/trello_flow/cleanup.rb +36 -0
- data/lib/trello_flow/cli.rb +62 -0
- data/lib/trello_flow/config.rb +52 -0
- data/lib/trello_flow/main.rb +62 -0
- data/lib/trello_flow/pull_request.rb +54 -0
- data/lib/trello_flow/repo.rb +21 -0
- data/lib/trello_flow/table/row.rb +36 -0
- data/lib/trello_flow/table.rb +34 -0
- data/lib/trello_flow/version.rb +3 -0
- data/lib/trello_flow.rb +14 -0
- data/trello_flow.gemspec +36 -0
- metadata +273 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8f0ce6169233ed20673ae5080ce673ddd14d4398
|
4
|
+
data.tar.gz: dc35673dc8731152e0d359d8a31adedf94e2a373
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1f4c4761746ec6e8a6a5aa68490c03959657f3053cc3d2db356bbea602c0e332c12dff98ff44d2cc1070dc7ffd5170b6485bbcd20e90f9a9f32bb8fe55aeedb6
|
7
|
+
data.tar.gz: cd43daa56ca0d8f689ae28c086da9b8fe6a361210a262d775cfc62bbf90c4e115cca08f9ae98dd931914cb7dc93953021063ccec5a858ea23093e59bd9f355b7
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
7
|
+
|
8
|
+
We are committed to making participation in this project a harassment-free
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
12
|
+
|
13
|
+
Examples of unacceptable behavior by participants include:
|
14
|
+
|
15
|
+
* The use of sexualized language or imagery
|
16
|
+
* Personal attacks
|
17
|
+
* Trolling or insulting/derogatory comments
|
18
|
+
* Public or private harassment
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
20
|
+
addresses, without explicit permission
|
21
|
+
* Other unethical or unprofessional conduct
|
22
|
+
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
+
threatening, offensive, or harmful.
|
28
|
+
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
+
Conduct may be permanently removed from the project team.
|
33
|
+
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
35
|
+
when an individual is representing the project or its community.
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
+
reported by contacting a project maintainer at jens@balvig.com. All
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
+
incident.
|
43
|
+
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
+
version 1.3.0, available at
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
+
|
48
|
+
[homepage]: http://contributor-covenant.org
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Jens Balvig
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# trello_flow
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
```bash
|
6
|
+
gem uninstall pt-flow dolma # if used
|
7
|
+
gem install trello_flow
|
8
|
+
```
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
```bash
|
13
|
+
git open # Open relevant card/all users card in browser
|
14
|
+
git start # shows list of cards user is member of
|
15
|
+
git start <card URL> # show checklist. Choosing items assigns self & creates branch
|
16
|
+
git start "Do this" # picking a card/checklist adds and starts item
|
17
|
+
git finish # checks off task, opens PR
|
18
|
+
git cleanup # cleans up merged card branches
|
19
|
+
```
|
20
|
+
|
21
|
+
|
22
|
+
## License
|
23
|
+
|
24
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/exe/git-cleanup
ADDED
data/exe/git-finish
ADDED
data/exe/git-open
ADDED
data/exe/git-start
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spyke"
|
2
|
+
require "trello_flow/api/json_parser"
|
3
|
+
|
4
|
+
module TrelloFlow
|
5
|
+
module Api
|
6
|
+
class Base < Spyke::Base
|
7
|
+
require "trello_flow/api/card"
|
8
|
+
require "trello_flow/api/checklist"
|
9
|
+
require "trello_flow/api/member"
|
10
|
+
require "trello_flow/api/item"
|
11
|
+
|
12
|
+
include_root_in_json false
|
13
|
+
cattr_accessor :token
|
14
|
+
|
15
|
+
def self.configure(key:, token:)
|
16
|
+
self.connection = Faraday.new(url: "https://api.trello.com/1", params: { key: key, token: token }) do |c|
|
17
|
+
c.request :json
|
18
|
+
c.use JSONParser
|
19
|
+
c.adapter Faraday.default_adapter
|
20
|
+
end
|
21
|
+
self.token = token
|
22
|
+
end
|
23
|
+
|
24
|
+
def position
|
25
|
+
self[:pos].to_f
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module TrelloFlow
|
2
|
+
module Api
|
3
|
+
class Card < Base
|
4
|
+
has_many :checklists
|
5
|
+
|
6
|
+
def self.fields
|
7
|
+
[:name]
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.find_by_url(url)
|
11
|
+
id = url.scan(/\/c\/(.+)\//).flatten.first
|
12
|
+
find(id)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.for(username)
|
16
|
+
with("members/:username/cards/open").where(username: username)
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_or_create_checklist
|
20
|
+
Table.new(checklists).pick || Checklist.create(idCard: id, name: "To-Do")
|
21
|
+
end
|
22
|
+
|
23
|
+
def url
|
24
|
+
attributes[:shortUrl]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "trello_flow/table"
|
2
|
+
|
3
|
+
module TrelloFlow
|
4
|
+
module Api
|
5
|
+
class Checklist < Base
|
6
|
+
belongs_to :card
|
7
|
+
#has_many :items, uri: "checklists/:checklist_id/checkItems"
|
8
|
+
|
9
|
+
def self.fields
|
10
|
+
[:name]
|
11
|
+
end
|
12
|
+
|
13
|
+
def select_or_create_item
|
14
|
+
if items.none?
|
15
|
+
item_name = Cli.ask("Input to-do [#{card.name}]:").presence || card.name
|
16
|
+
add_item(item_name)
|
17
|
+
else
|
18
|
+
Table.new(items).pick("#{card.name} (#{name})")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def items
|
23
|
+
attributes[:checkItems].map do |attr|
|
24
|
+
Item.new attr.merge(checklist_id: id)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def card_id
|
29
|
+
attributes[:idCard]
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_item(name)
|
33
|
+
Item.with("checklists/:checklist_id/checkItems").where(checklist_id: id).create(name: name)
|
34
|
+
# items.create(name: name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module TrelloFlow
|
2
|
+
module Api
|
3
|
+
class Item < Base
|
4
|
+
delegate :card, :card_id, to: :checklist
|
5
|
+
|
6
|
+
def self.fields
|
7
|
+
[:description, :owners]
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.find(checklist_id, item_id)
|
11
|
+
with("checklists/#{checklist_id}/checkItems/#{item_id}").find_one
|
12
|
+
end
|
13
|
+
|
14
|
+
def description
|
15
|
+
if complete?
|
16
|
+
checkmark + name_without_mentions
|
17
|
+
else
|
18
|
+
name_without_mentions
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def owners
|
23
|
+
mentions.join(", ")
|
24
|
+
end
|
25
|
+
|
26
|
+
def color
|
27
|
+
:green if complete?
|
28
|
+
end
|
29
|
+
|
30
|
+
def assign(owner)
|
31
|
+
return if mentions.include?(owner)
|
32
|
+
self.class.request :put, "cards/#{card_id}/checklist/#{checklist_id}/checkItem/#{id}/name", value: name_without_mentions + " @#{owner}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def complete
|
36
|
+
self.class.request :put, "cards/#{card_id}/checklist/#{checklist_id}/checkItem/#{id}/state", value: "complete"
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_param
|
40
|
+
name_without_mentions.parameterize[0..50]
|
41
|
+
end
|
42
|
+
|
43
|
+
def name_without_mentions
|
44
|
+
(name.split - mentions).join(" ").strip
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def checklist
|
50
|
+
@_checklist ||= Checklist.find checklist_id
|
51
|
+
end
|
52
|
+
|
53
|
+
def checklist_id
|
54
|
+
attributes[:idChecklist]
|
55
|
+
end
|
56
|
+
|
57
|
+
def mentions
|
58
|
+
name.scan(/(@\S+)/).flatten
|
59
|
+
end
|
60
|
+
|
61
|
+
def checkmark
|
62
|
+
"\u2713 "
|
63
|
+
end
|
64
|
+
|
65
|
+
def complete?
|
66
|
+
state == "complete"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "active_support/core_ext/string/inflections"
|
2
|
+
require "trello_flow/pull_request"
|
3
|
+
|
4
|
+
module TrelloFlow
|
5
|
+
class Branch
|
6
|
+
def initialize(name)
|
7
|
+
@name = name
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.current
|
11
|
+
new Cli.read("git rev-parse --abbrev-ref HEAD")
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.from_item(item)
|
15
|
+
new("#{current.target}.#{item.to_param}.#{item.checklist_id}-#{item.id}")
|
16
|
+
end
|
17
|
+
|
18
|
+
def checkout
|
19
|
+
Cli.run "git checkout -b #{name}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def push
|
23
|
+
Cli.run "git push origin #{name} -u"
|
24
|
+
end
|
25
|
+
|
26
|
+
def open_pull_request
|
27
|
+
PullRequest.new(current_item, from: name, target: target).open
|
28
|
+
end
|
29
|
+
|
30
|
+
def complete_current_item
|
31
|
+
current_item.complete
|
32
|
+
end
|
33
|
+
|
34
|
+
def open_trello(username)
|
35
|
+
if current_item
|
36
|
+
Cli.open_url current_item.card.url
|
37
|
+
else
|
38
|
+
Cli.open_url "https://trello.com/#{username}/cards"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def target
|
43
|
+
name.split('.').first
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :name
|
49
|
+
|
50
|
+
def ids
|
51
|
+
name.split(".").last.split("-")
|
52
|
+
end
|
53
|
+
|
54
|
+
def checklist_id
|
55
|
+
ids.first
|
56
|
+
end
|
57
|
+
|
58
|
+
def item_id
|
59
|
+
ids.last if ids.size == 2
|
60
|
+
end
|
61
|
+
|
62
|
+
def current_item
|
63
|
+
@_current_item ||= Api::Item.find(checklist_id, item_id) if item_id
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module TrelloFlow
|
2
|
+
class Cleanup
|
3
|
+
def initialize(target)
|
4
|
+
@target = target
|
5
|
+
end
|
6
|
+
|
7
|
+
def run
|
8
|
+
Cli.title "Cleaning merged story branches for [#{target}]"
|
9
|
+
update_remotes
|
10
|
+
remove_fully_merged_local_branches
|
11
|
+
remove_fully_merged_remote_branches
|
12
|
+
Cli.success "Deleted branches merged with [#{target}]"
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :target
|
18
|
+
|
19
|
+
def update_remotes
|
20
|
+
Cli.run "git fetch"
|
21
|
+
Cli.run "git remote prune origin"
|
22
|
+
end
|
23
|
+
|
24
|
+
def remove_fully_merged_local_branches
|
25
|
+
Cli.run "git branch --merged origin/#{target} | grep '#{filter}' | xargs git branch -D"
|
26
|
+
end
|
27
|
+
|
28
|
+
def remove_fully_merged_remote_branches
|
29
|
+
Cli.run "git branch -r --merged origin/#{target} | sed 's/ *origin\\///' | grep '#{filter}' | xargs -I% git push origin :%"
|
30
|
+
end
|
31
|
+
|
32
|
+
def filter
|
33
|
+
"^ *#{target}.\\+$"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "colored"
|
2
|
+
require "forwardable"
|
3
|
+
require "highline"
|
4
|
+
require "hirb-colors"
|
5
|
+
require "hirb"
|
6
|
+
|
7
|
+
module TrelloFlow
|
8
|
+
class Cli
|
9
|
+
class << self
|
10
|
+
extend Forwardable
|
11
|
+
def_delegators :client, :table, :open_url, :say, :success, :ask, :title, :error, :run, :read
|
12
|
+
attr_accessor :client
|
13
|
+
end
|
14
|
+
|
15
|
+
self.client = Cli.new
|
16
|
+
|
17
|
+
def table(items)
|
18
|
+
puts Hirb::Helpers::AutoTable.render(items, unicode: true)
|
19
|
+
end
|
20
|
+
|
21
|
+
def open_url(url)
|
22
|
+
return title(url) if ENV['BROWSER'] == 'echo'
|
23
|
+
`open \"#{url}\"`
|
24
|
+
end
|
25
|
+
|
26
|
+
def say(*args)
|
27
|
+
highline.say(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def success(message)
|
31
|
+
highline.say(message.green.bold)
|
32
|
+
end
|
33
|
+
|
34
|
+
def ask(message, type = nil)
|
35
|
+
highline.ask(message, type)
|
36
|
+
end
|
37
|
+
|
38
|
+
def title(message)
|
39
|
+
highline.say(message.bold)
|
40
|
+
end
|
41
|
+
|
42
|
+
def error(message)
|
43
|
+
say(message.red.bold)
|
44
|
+
exit(false)
|
45
|
+
end
|
46
|
+
|
47
|
+
def run(command)
|
48
|
+
title(command)
|
49
|
+
system(command) || error("Error running: #{command}")
|
50
|
+
end
|
51
|
+
|
52
|
+
def read(command)
|
53
|
+
`#{command}`.strip.presence
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def highline
|
59
|
+
@_highline ||= HighLine.new
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "trello_flow/api/base"
|
2
|
+
|
3
|
+
module TrelloFlow
|
4
|
+
class Config
|
5
|
+
PATH = ENV["HOME"] + "/.trello_flow"
|
6
|
+
|
7
|
+
def initialize(data = load_data || {})
|
8
|
+
@data = data
|
9
|
+
Api::Base.configure(key: key, token: token)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
attr_reader :data
|
15
|
+
|
16
|
+
def load_data
|
17
|
+
YAML.load(File.read(PATH))
|
18
|
+
rescue
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def key
|
23
|
+
@_key ||= data[:key] || configure_key
|
24
|
+
end
|
25
|
+
|
26
|
+
def token
|
27
|
+
@_token ||= data[:token] || configure_token
|
28
|
+
end
|
29
|
+
|
30
|
+
def configure_key
|
31
|
+
Cli.ask "Press enter to setup Trello for this project (will open public key url)"
|
32
|
+
Cli.open_url "https://trello.com/app-key"
|
33
|
+
save :key, Cli.ask("Input Developer API key")
|
34
|
+
end
|
35
|
+
|
36
|
+
def configure_token
|
37
|
+
Cli.open_url authorize_url(key)
|
38
|
+
save :token, Cli.ask("Input member token")
|
39
|
+
end
|
40
|
+
|
41
|
+
def save(key, value)
|
42
|
+
data[key] = value
|
43
|
+
File.new(PATH, "w") unless File.exists?(PATH)
|
44
|
+
File.open(PATH, "w") { |f| f.write(data.to_yaml) }
|
45
|
+
value
|
46
|
+
end
|
47
|
+
|
48
|
+
def authorize_url(key)
|
49
|
+
"https://trello.com/1/authorize?key=#{key}&name=Trello-Flow&scope=read,write,account&expiration=never&response_type=token"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module TrelloFlow
|
2
|
+
class Main
|
3
|
+
def initialize(config = Config.new)
|
4
|
+
@config = config
|
5
|
+
end
|
6
|
+
|
7
|
+
def start(input)
|
8
|
+
if input.to_s.start_with?("http")
|
9
|
+
start_with_url(input)
|
10
|
+
elsif input.present?
|
11
|
+
start_new_item(input)
|
12
|
+
else
|
13
|
+
start_blank
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def open
|
18
|
+
Branch.current.open_trello(username)
|
19
|
+
end
|
20
|
+
|
21
|
+
def finish
|
22
|
+
branch = Branch.current
|
23
|
+
branch.push
|
24
|
+
branch.open_pull_request
|
25
|
+
branch.complete_current_item
|
26
|
+
end
|
27
|
+
|
28
|
+
def cleanup
|
29
|
+
Cleanup.new(Branch.current.target).run
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def start_with_url(url)
|
35
|
+
card = Api::Card.find_by_url(url)
|
36
|
+
checklist = card.find_or_create_checklist
|
37
|
+
item = checklist.select_or_create_item
|
38
|
+
item.assign(username)
|
39
|
+
Branch.from_item(item).checkout
|
40
|
+
end
|
41
|
+
|
42
|
+
def start_blank
|
43
|
+
card = Table.new(Api::Card.for(username)).pick
|
44
|
+
checklist = card.find_or_create_checklist
|
45
|
+
item = checklist.select_or_create_item
|
46
|
+
item.assign(username)
|
47
|
+
Branch.from_item(item).checkout
|
48
|
+
end
|
49
|
+
|
50
|
+
def start_new_item(name)
|
51
|
+
card = Table.new(Api::Card.for(username)).pick
|
52
|
+
checklist = card.find_or_create_checklist
|
53
|
+
item = checklist.add_item(name)
|
54
|
+
item.assign(username)
|
55
|
+
Branch.from_item(item).checkout
|
56
|
+
end
|
57
|
+
|
58
|
+
def username
|
59
|
+
@_username ||= Api::Member.current.username
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "trello_flow/repo"
|
2
|
+
|
3
|
+
module TrelloFlow
|
4
|
+
class PullRequest
|
5
|
+
def initialize(item, from:, target:)
|
6
|
+
@item = item
|
7
|
+
@from = from
|
8
|
+
@target = target
|
9
|
+
end
|
10
|
+
|
11
|
+
def open
|
12
|
+
Cli.open_url url
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :item, :from, :target
|
18
|
+
|
19
|
+
def url
|
20
|
+
repo.url + "/compare/#{target}...#{from}?expand=1&title=#{escape title_with_prefixes}&body=#{escape body}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def title
|
24
|
+
item.name_without_mentions.gsub('"',"'")
|
25
|
+
end
|
26
|
+
|
27
|
+
def body
|
28
|
+
"Trello: #{item.card.url}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def prefixes
|
32
|
+
prefixes = []
|
33
|
+
# prefixes << "[WIP]" if @options[:wip]
|
34
|
+
prefixes << "[#{target.titleize}]" if release_branch?
|
35
|
+
prefixes.join(" ")
|
36
|
+
end
|
37
|
+
|
38
|
+
def release_branch?
|
39
|
+
target != "master"
|
40
|
+
end
|
41
|
+
|
42
|
+
def title_with_prefixes
|
43
|
+
"#{prefixes} #{title}".strip
|
44
|
+
end
|
45
|
+
|
46
|
+
def escape(text)
|
47
|
+
URI.escape text.strip
|
48
|
+
end
|
49
|
+
|
50
|
+
def repo
|
51
|
+
@_repo ||= Repo.new
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module TrelloFlow
|
2
|
+
class Repo
|
3
|
+
def user
|
4
|
+
path.split('/').first
|
5
|
+
end
|
6
|
+
|
7
|
+
def name
|
8
|
+
path.split('/').last
|
9
|
+
end
|
10
|
+
|
11
|
+
def url
|
12
|
+
"https://github.com/#{user}/#{name}"
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def path
|
18
|
+
@_path ||= Cli.read("git config --get remote.origin.url").match(/github.com[:\/](\S+\/\S+)\.git/)[1]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module TrelloFlow
|
2
|
+
class Table
|
3
|
+
class Row
|
4
|
+
attr_reader :num
|
5
|
+
|
6
|
+
def initialize(record, index)
|
7
|
+
@record = record
|
8
|
+
@num = index + 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_h
|
12
|
+
result = { "#": @num }
|
13
|
+
fields.each do |field|
|
14
|
+
result[field] = colorize(@record.send(field))
|
15
|
+
end
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def colorize(str)
|
22
|
+
return str unless str.respond_to?(color)
|
23
|
+
str.send(color)
|
24
|
+
end
|
25
|
+
|
26
|
+
def color
|
27
|
+
custom_color = @record.color if @record.respond_to?(:color)
|
28
|
+
custom_color || :white
|
29
|
+
end
|
30
|
+
|
31
|
+
def fields
|
32
|
+
@fields ||= @record.class.fields
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "trello_flow/table/row"
|
2
|
+
|
3
|
+
module TrelloFlow
|
4
|
+
class Table
|
5
|
+
def initialize(records)
|
6
|
+
@records = records.to_a.sort_by(&:position)
|
7
|
+
end
|
8
|
+
|
9
|
+
def pick(title = nil)
|
10
|
+
return if @records.none?
|
11
|
+
return @records.first if @records.one?
|
12
|
+
Cli.title title if title
|
13
|
+
render_table
|
14
|
+
index = Cli.ask("Pick one:", Integer)
|
15
|
+
@records[index - 1]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def render_table
|
21
|
+
if @records.size > 0
|
22
|
+
Cli.table rows
|
23
|
+
else
|
24
|
+
Cli.say "No records found"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def rows
|
29
|
+
@records.each_with_index.map do |record, index|
|
30
|
+
Row.new(record, index).to_h
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/trello_flow.rb
ADDED
data/trello_flow.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "trello_flow/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "trello_flow"
|
8
|
+
spec.version = TrelloFlow::VERSION
|
9
|
+
spec.authors = ["Jens Balvig"]
|
10
|
+
spec.email = ["jens@balvig.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{GitHub/Trello flow gemified.}
|
13
|
+
spec.description = %q{GitHub/Trello flow gemified.}
|
14
|
+
spec.homepage = "https://github.com/balvig/trello-flow"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
25
|
+
spec.add_development_dependency 'minitest-line'
|
26
|
+
spec.add_development_dependency 'multi_json'
|
27
|
+
spec.add_development_dependency "pry"
|
28
|
+
spec.add_development_dependency 'webmock'
|
29
|
+
spec.add_dependency "colored"
|
30
|
+
spec.add_dependency "highline"
|
31
|
+
spec.add_dependency "hirb"
|
32
|
+
spec.add_dependency "hirb-colors"
|
33
|
+
spec.add_dependency "hirb-unicode"
|
34
|
+
spec.add_dependency "launchy"
|
35
|
+
spec.add_dependency "spyke"
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,273 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trello_flow
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jens Balvig
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-10-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-line
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: multi_json
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: colored
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: highline
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: hirb
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: hirb-colors
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: hirb-unicode
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: launchy
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :runtime
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: spyke
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :runtime
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
209
|
+
description: GitHub/Trello flow gemified.
|
210
|
+
email:
|
211
|
+
- jens@balvig.com
|
212
|
+
executables:
|
213
|
+
- git-cleanup
|
214
|
+
- git-finish
|
215
|
+
- git-open
|
216
|
+
- git-start
|
217
|
+
extensions: []
|
218
|
+
extra_rdoc_files: []
|
219
|
+
files:
|
220
|
+
- ".gitignore"
|
221
|
+
- ".travis.yml"
|
222
|
+
- CODE_OF_CONDUCT.md
|
223
|
+
- Gemfile
|
224
|
+
- LICENSE.txt
|
225
|
+
- README.md
|
226
|
+
- Rakefile
|
227
|
+
- exe/git-cleanup
|
228
|
+
- exe/git-finish
|
229
|
+
- exe/git-open
|
230
|
+
- exe/git-start
|
231
|
+
- lib/trello_flow.rb
|
232
|
+
- lib/trello_flow/api/base.rb
|
233
|
+
- lib/trello_flow/api/card.rb
|
234
|
+
- lib/trello_flow/api/checklist.rb
|
235
|
+
- lib/trello_flow/api/item.rb
|
236
|
+
- lib/trello_flow/api/json_parser.rb
|
237
|
+
- lib/trello_flow/api/member.rb
|
238
|
+
- lib/trello_flow/branch.rb
|
239
|
+
- lib/trello_flow/cleanup.rb
|
240
|
+
- lib/trello_flow/cli.rb
|
241
|
+
- lib/trello_flow/config.rb
|
242
|
+
- lib/trello_flow/main.rb
|
243
|
+
- lib/trello_flow/pull_request.rb
|
244
|
+
- lib/trello_flow/repo.rb
|
245
|
+
- lib/trello_flow/table.rb
|
246
|
+
- lib/trello_flow/table/row.rb
|
247
|
+
- lib/trello_flow/version.rb
|
248
|
+
- trello_flow.gemspec
|
249
|
+
homepage: https://github.com/balvig/trello-flow
|
250
|
+
licenses:
|
251
|
+
- MIT
|
252
|
+
metadata: {}
|
253
|
+
post_install_message:
|
254
|
+
rdoc_options: []
|
255
|
+
require_paths:
|
256
|
+
- lib
|
257
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
258
|
+
requirements:
|
259
|
+
- - ">="
|
260
|
+
- !ruby/object:Gem::Version
|
261
|
+
version: '0'
|
262
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
263
|
+
requirements:
|
264
|
+
- - ">="
|
265
|
+
- !ruby/object:Gem::Version
|
266
|
+
version: '0'
|
267
|
+
requirements: []
|
268
|
+
rubyforge_project:
|
269
|
+
rubygems_version: 2.5.1
|
270
|
+
signing_key:
|
271
|
+
specification_version: 4
|
272
|
+
summary: GitHub/Trello flow gemified.
|
273
|
+
test_files: []
|