trellish 0.0.15 → 0.0.18

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.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Trellish
2
2
 
3
- Trellish is used to finish a Trello card. It does everything necessary to move a development card from the In Progress list to the QA list.
3
+ Trellish is used to start and finish a Trello card. It does everything necessary to move a development card from "Next up" to "In Progress" when you start work on a card and again from "In Progress" to "QA" when you finish a card.
4
4
 
5
5
  ## Installation
6
6
 
@@ -16,9 +16,9 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install trellish
18
18
 
19
- ## Usage
19
+ ## Setup
20
20
 
21
- Create a trellish.yml file in your current directory or home directory. Set it up like this:
21
+ Create a `./trellish.yml`, `~/trellish.yml` or `~/.trellish` file with the contents of [trellish.example.yml](trellish/blob/master/trellish.example.yml). Set it up like this:
22
22
 
23
23
  1. Sign in to Trello and go to https://trello.com/1/appKey/generate.
24
24
  1. Copy "Key" from that page to trello\_api\_key.
@@ -28,18 +28,49 @@ Create a trellish.yml file in your current directory or home directory. Set it u
28
28
  1. Run: `curl -u 'username' -d '{"scopes":["repo"],"note":"Trellish"}' https://api.github.com/authorizations`
29
29
  1. Copy the token parameter from the response to github\_oauth\_token.
30
30
 
31
- `git checkout` the topic branch for the card you are finishing. Then do this:
31
+ Optionally, Trellish can announce the starting and finishing of cards on 37signal's [Campfire](http://campfirenow.com/). To enable this:
32
+
33
+ 1. Sign in to Campfire and go to your "my info" page. You can find the link in the upper-right corner.
34
+ 1. Copy your subdomain name to campfire\_subdomain.
35
+ 1. Copy your API authentication token to campfire\_token.
36
+ 1. Specify the room name in campfire\_room.
37
+
38
+ ## Usage
39
+
40
+ By default, Trellish expects a Trello board named `Current` with 3 lists: `Next up`, `In progress`, and `QA`. You can change these defaults using the Trellish config file.
41
+
42
+ To start work on a card:
43
+
44
+ trellish start [Trello card id or URL]
45
+
46
+ This will:
47
+
48
+ - move the card from `Next up` to `In progress`,
49
+ - add you as a member,
50
+ - create a local git branch named using your git initials and the card's title.
51
+
52
+ If you don't provide a card id or URL on the command line, trellish shows you the cards in `Next up` and prompts you to select one, like so:
53
+
54
+ Select a card:
55
+ 1. BUG: crash adding a comment
56
+ 2. users can select an avatar
57
+ 3. add iPad integration tests
58
+ >
59
+
60
+ When you're done working on a card, finish it using:
32
61
 
33
- trellish https://trello.com/c/a3Wbcde4
62
+ trellish finish [Trello card id or URL]
34
63
 
35
- or alternately:
64
+ Like:
36
65
 
37
- trellish a3Wbcde4
66
+ trellish finish https://trello.com/c/a3Wbcde4
67
+ trellish finish a3Wbcde4
68
+ trellish finish
38
69
 
39
70
  This will:
40
71
 
41
- - create a pull request to merge your topic branch into master
42
- - add a link to the pull request to the beginning of the card description
72
+ - create a pull request to merge your topic branch into master (with a description linking back to the card)
73
+ - add a link to the pull request from the card's description
43
74
  - remove everyone from the card
44
75
  - move the card to the QA list
45
76
 
@@ -1,32 +1,46 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: utf-8
2
3
 
4
+ require 'readline'
3
5
  require 'trellish'
4
6
  require 'trellish/card'
5
7
  require 'yaml'
6
8
 
7
- if ARGV[0].nil?
8
- Trellish.logger.error "Please provide a Trello card id or URL."
9
- exit
10
- end
9
+ # process config file
11
10
 
12
- config_file = if File.exists?('trellish.yml')
13
- YAML.load(File.read('trellish.yml'))
14
- elsif File.exists?(File.expand_path('~/trellish.yml'))
15
- YAML.load(File.read(File.expand_path('~/trellish.yml')))
16
- end
11
+ config_paths = %w(trellish.yml ~/trellish.yml ~/.trellish)
12
+ config_filepath = config_paths.collect { |e| File.expand_path(e) }.find { |e| File.exists?(e) }
13
+ config_file = YAML.load(File.read(config_filepath)) if config_filepath
17
14
 
18
15
  unless config_file
19
- Trellish.logger.error "Could not locate trellish.yml file in current directory or home directory."
16
+ Trellish.logger.error "Could not locate your settings in ./trellish.yml, ~/trellish.yml, or ~/.trellish"
20
17
  exit
21
18
  end
22
19
 
23
- Trellish.configure(
24
- trello_api_key: config_file['trello_api_key'],
25
- trello_oauth_secret: config_file['trello_oauth_secret'],
26
- trello_oauth_token: config_file['trello_oauth_token'],
27
- github_oauth_token: config_file['github_oauth_token'],
28
- git_base_branch: config_file['git_base_branch'] || 'master',
29
- qa_list_name: config_file['qa_list_name'] || 'QA')
20
+ Trellish.configure(config_file)
21
+
22
+ # parse command-line arguments
23
+
24
+ case ARGV[0]
30
25
 
31
- card = Trellish::Card.new(ARGV[0])
32
- card.finish
26
+ when 'start'
27
+ card =
28
+ if ARGV[1]
29
+ Trellish::Card.new(ARGV[1])
30
+ else
31
+ Trellish::Card.select_from_list(Trellish.config[:next_up_list_name], false)
32
+ end
33
+ puts %Q(Starting card “#{card.name}”)
34
+ card.start
35
+
36
+ when 'finish'
37
+ card =
38
+ if ARGV[1]
39
+ Trellish::Card.new(ARGV[1])
40
+ else
41
+ Trellish::Card.select_from_list(Trellish.config[:in_progress_list_name], true)
42
+ end
43
+ puts %Q(Finishing card “#{card.name}”)
44
+ card.finish
45
+
46
+ end
@@ -12,8 +12,14 @@ module Trellish
12
12
  trello_oauth_secret: 'TRELLO_OAUTH_SECRET',
13
13
  trello_oauth_token: 'TRELLO_OAUTH_TOKEN',
14
14
  github_oauth_token: 'GITHUB_OAUTH_TOKEN',
15
- git_base_branch: 'GIT_BASE_BRANCH',
16
- qa_list_name: 'QA'
15
+ git_base_branch: 'master',
16
+ board_name: 'Current',
17
+ next_up_list_name: 'Next up',
18
+ in_progress_list_name: 'In progress',
19
+ qa_list_name: 'QA',
20
+ campfire_subdomain: nil,
21
+ campfire_token: nil,
22
+ campfire_room: nil
17
23
  }
18
24
 
19
25
  @valid_config_keys = @config.keys
@@ -8,7 +8,11 @@ module Trellish
8
8
 
9
9
  Trello::Authorization.const_set :AuthPolicy, OAuthPolicy
10
10
 
11
+ @@member = nil
12
+
11
13
  def self.authorize
14
+ return @@member if @@member
15
+
12
16
  OAuthPolicy.consumer_credential = OAuthCredential.new(
13
17
  Trellish.config[:trello_api_key],
14
18
  Trellish.config[:trello_oauth_secret])
@@ -17,7 +21,8 @@ module Trellish
17
21
  # Test that the user is authorized
18
22
  begin
19
23
  member_id = Trello::Token.find(OAuthPolicy.token.key).member_id
20
- Member.find(member_id)
24
+ @@member = Member.find(member_id)
25
+ @@member
21
26
  rescue
22
27
  Trellish.logger.error "Unable to authorize access to Trello API."
23
28
  exit
@@ -0,0 +1,24 @@
1
+ require 'tinder'
2
+
3
+ module Trellish
4
+ module Campfire
5
+
6
+ def announce(message)
7
+ room.speak message if room
8
+ end
9
+
10
+ private
11
+
12
+ def room
13
+ @room ||=
14
+ if [:campfire_subdomain, :campfire_token, :campfire_room].all? { |s| Trellish.config[s] }
15
+ campfire = Tinder::Campfire.new Trellish.config[:campfire_subdomain], :token => Trellish.config[:campfire_token]
16
+ campfire.rooms.find { |room| room.name == Trellish.config[:campfire_room] }
17
+ end
18
+ rescue
19
+ Trellish.logger.error "Unable to access Campfire. Is your subdomain, token, and room name correct?"
20
+ exit
21
+ end
22
+
23
+ end
24
+ end
@@ -1,41 +1,130 @@
1
+ # encoding: utf-8
2
+
3
+ require 'trellish/campfire'
1
4
  require 'trellish/git'
2
5
 
3
6
  module Trellish
4
7
  class Card
5
8
  include Trello
6
9
  include Trellish::Git
10
+ include Trellish::Campfire
11
+
12
+ def self.select_from_list(list_name, assigned_to_me = false)
13
+ me = Trellish::Auth.authorize
14
+ boards = me.boards(filter: :open)
15
+ current_board = boards.find { |board| board.name == Trellish.config[:board_name] }
16
+ if current_board.nil?
17
+ Trellish.logger.error "Unable to find a board named `#{Trellish.config[:board_name]}`."
18
+ exit
19
+ end
20
+
21
+ list = current_board.lists.find { |list| list.name == list_name }
22
+ if list.nil?
23
+ Trellish.logger.error "Unable to find a list named `#{list_name}` on board `#{Trellish.config[:board_name]}`."
24
+ exit
25
+ end
26
+
27
+ cards = list.cards
28
+
29
+ if assigned_to_me
30
+ cards = cards.find_all { |card| card.member_ids.include?(me.id) }
31
+ end
32
+
33
+ case cards.length
34
+ when 0
35
+ if assigned_to_me
36
+ Trellish.logger.error "There are no cards assigned to you in the list `#{list_name}`"
37
+ else
38
+ Trellish.logger.error "There are no cards in the list `#{list_name}`"
39
+ end
40
+ exit
41
+ when 1
42
+ index = 0
43
+ else
44
+ puts "\nSelect a card:"
45
+ cards.each_with_index { |card, index| puts "#{index+1}. #{card.name}" }
46
+ index = Readline.readline("> ")
47
+ exit if index.blank?
48
+ index = index.to_i - 1
49
+ end
50
+
51
+ Trellish::Card.new( cards[index].id )
52
+ end
7
53
 
8
54
  def initialize(card_id_or_url)
9
55
  @member = Trellish::Auth.authorize
10
56
  @card = Trello::Card.find(parse_card_id(card_id_or_url))
11
57
  end
12
58
 
59
+ def add_me_as_member
60
+ @card.add_member(@member) unless @card.member_ids.include?(@member.id)
61
+ end
62
+
13
63
  def add_pull_request_link
14
- @card.description = "[Pull Request] (#{github_pull_request_url})\n\n#{@card.description}"
15
- @card.save
64
+ # Unfortunately, changing the card's description changes the card's URL, which breaks
65
+ # the link from the pull request, and our announcements to Campfire. Instead, add
66
+ # a comment to the pull request.
67
+ # @card.description = "[Pull Request](#{github_pull_request_url})\n\n#{@card.description}"
68
+ # @card.update!
69
+ message = "Pull request is at #{github_pull_request_url}"
70
+ @card.add_comment message
71
+ end
72
+
73
+ def create_local_branch
74
+ branch_name = "#{git_user_initials}-#{short_name}"
75
+ git_create_local_branch(branch_name)
16
76
  end
17
77
 
18
78
  def finish
79
+ if !current_git_branch_is_up_to_date?
80
+ finish = Readline.readline("Your remote branch isn’t up-to-date. Finish anyway? [y,N] ")
81
+ exit unless ['y','yes'].include?(finish.strip.downcase)
82
+ end
83
+
19
84
  add_pull_request_link
20
85
  remove_all
21
86
  move_to_qa
87
+ announce %Q([Trellish] Finished card “#{@card.name}” #{@card.url}. The pull request is at #{github_pull_request_url})
22
88
  end
23
89
 
24
90
  def move_to_qa
25
- qa_list = @card.board.lists.find { |list| list.name == Trellish.config[:qa_list_name] }
26
- if qa_list
27
- @card.move_to_list(qa_list)
28
- else
29
- Trellish.logger.warn "Unable to move card to #{Trellish.config[:qa_list_name]} list. No list named #{Trellish.config[:qa_list_name]} found."
30
- end
91
+ move_to_list(Trellish.config[:qa_list_name])
92
+ end
93
+
94
+ def move_to_in_progress
95
+ move_to_list(Trellish.config[:in_progress_list_name])
96
+ end
97
+
98
+ def name
99
+ @card.name
31
100
  end
32
101
 
33
102
  def remove_all
34
103
  @card.remove_all_members
35
104
  end
36
105
 
106
+ def short_name
107
+ name.strip.downcase.tr(' ','-').gsub(/[^0-9A-Za-z\-]/, '')[0..30]
108
+ end
109
+
110
+ def start
111
+ move_to_in_progress
112
+ add_me_as_member
113
+ create_local_branch
114
+ announce %Q([Trellish] Starting card “#{@card.name}” #{@card.url})
115
+ end
116
+
37
117
  private
38
118
 
119
+ def move_to_list(list_name)
120
+ list = @card.board.lists.find { |list| list.name == list_name }
121
+ if list
122
+ @card.move_to_list(list)
123
+ else
124
+ Trellish.logger.warn "Unable to move card to #{list_name} list. No list named #{list_name} found."
125
+ end
126
+ end
127
+
39
128
  def parse_card_id(card_id_or_url)
40
129
  card_id_or_url.match(/[A-Za-z0-9]*$/)[0]
41
130
  end
@@ -3,10 +3,6 @@ require 'faraday'
3
3
  module Trellish
4
4
  module Git
5
5
 
6
- def current_git_branch
7
- @current_git_branch ||= `cat .git/head`.split('/').last.strip
8
- end
9
-
10
6
  def github_pull_request_url
11
7
  return @github_pull_request_url if @github_pull_request_url
12
8
  conn = Faraday.new(:url => 'https://api.github.com', :ssl => {:ca_file => '/System/Library/OpenSSL/certs/ca-certificates.crt'}) do |faraday|
@@ -20,7 +16,8 @@ module Trellish
20
16
  req.headers['Authorization'] = "token #{Trellish.config[:github_oauth_token]}"
21
17
  req.body = {
22
18
  title: @card.name,
23
- base: Trellish.config[:git_base_branch],
19
+ body: "[Trello card](#{@card.url})",
20
+ base: git_base_branch,
24
21
  head: "#{git_repository_owner}:#{current_git_branch}"
25
22
  }.to_json
26
23
  end
@@ -43,8 +40,65 @@ module Trellish
43
40
  @git_repository_owner ||= matches[1]
44
41
  end
45
42
 
43
+ def git_create_local_branch(branch_name)
44
+ `git checkout -b #{branch_name} #{git_base_branch}`
45
+ rescue
46
+ Trellish.logger.warn "Failed to create a local git branch named #{branch_name}."
47
+ end
48
+
49
+ def current_git_branch_is_up_to_date?
50
+ git_remote_up_to_date?(current_git_branch)
51
+ end
52
+
53
+ def git_user_initials
54
+ return @user_initials if @user_initials
55
+ username = presence(`git config github.user`) || presence(`git config user.email`) || presence(`whoami`)
56
+ @user_initials = username[0..2]
57
+ end
58
+
59
+ private
60
+
61
+ def current_git_branch
62
+ @current_git_branch ||= `cat #{git_dir}/head`.split('/').last.strip
63
+ end
64
+
65
+ def git_base_branch
66
+ Trellish.config[:git_base_branch]
67
+ end
68
+
69
+ def git_dir
70
+ return @git_dir if @git_dir
71
+ path = `git rev-parse --git-dir`.strip
72
+ if path[/^fatal/]
73
+ Trellish.logger.error "Failed to find your git repository."
74
+ exit
75
+ end
76
+ @git_dir = path
77
+ end
78
+
79
+ def git_hash_for_ref(ref)
80
+ `git show-ref --hash #{ref}`.strip
81
+ end
82
+
83
+ def git_remote_up_to_date?(local_branch_name)
84
+ remote_branch_name = git_remote_branch_for_local_branch(local_branch_name)
85
+
86
+ local_hash = git_hash_for_ref("heads/#{local_branch_name}")
87
+ remote_hash = git_hash_for_ref("remotes/#{remote_branch_name}")
88
+
89
+ local_hash == remote_hash
90
+ end
91
+
92
+ def git_remote_branch_for_local_branch(local_branch_name)
93
+ `git for-each-ref --format='%(upstream:short)' refs/heads/#{local_branch_name}`.strip
94
+ end
95
+
46
96
  def matches
47
- @matches ||= matches = remote_url.match(%r|^git@github.com:([^/]*)\/([^\.]*)\.git$|)
97
+ @matches ||= remote_url.match(%r|^git@github.com:([^/]*)\/([^\.]*)\.git$|)
98
+ end
99
+
100
+ def presence(s)
101
+ s.strip if s && !s.strip.empty?
48
102
  end
49
103
 
50
104
  def remote_url
@@ -1,3 +1,3 @@
1
1
  module Trellish
2
- VERSION = "0.0.15"
2
+ VERSION = "0.0.18"
3
3
  end
@@ -18,5 +18,15 @@ github_oauth_token: numbers_and_letters_and_stuff
18
18
  # The branch you want your changes merged into
19
19
  git_base_branch: master
20
20
 
21
- # Name of your QA list in Trello
21
+ # Name of your Trello board
22
+ board_name: Current
23
+
24
+ # Names of your Next up, In progress, and QA lists in Trello
25
+ next_up_list_name: Next up
26
+ in_progress_list_name: In progress
22
27
  qa_list_name: QA
28
+
29
+ # Campfire subdomain, room & your token
30
+ campfire_subdomain: subdomain
31
+ campfire_token: 1111111111111111111111111111111111111111
32
+ campfire_room: Development
@@ -17,4 +17,5 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_dependency 'oauth2', '>=0.7.0'
19
19
  gem.add_dependency 'ruby-trello-wgibbs', '>=0.4.4'
20
+ gem.add_dependency 'tinder', '>=1.9.1'
20
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trellish
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.0.18
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-17 00:00:00.000000000 Z
12
+ date: 2013-01-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: oauth2
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: 0.4.4
46
+ - !ruby/object:Gem::Dependency
47
+ name: tinder
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 1.9.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.9.1
46
62
  description: Create a pull request, put link to it on the card, remove everyone and
47
63
  move the card to the QA list
48
64
  email:
@@ -61,6 +77,7 @@ files:
61
77
  - bin/trellish
62
78
  - lib/trellish.rb
63
79
  - lib/trellish/auth.rb
80
+ - lib/trellish/campfire.rb
64
81
  - lib/trellish/card.rb
65
82
  - lib/trellish/git.rb
66
83
  - lib/trellish/version.rb