git_trello_post_commit 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 471b1b00e71f8ff30557b7b4aafcfea9bff20e0b
4
- data.tar.gz: 5259e88d12923ffc55720fb1e22c9251685fe9dd
3
+ metadata.gz: 83151148c861df200b9f55ce1d2c435b06166ae8
4
+ data.tar.gz: 2a62f11e42798ed4a432a4cdbc398d554abd72c3
5
5
  SHA512:
6
- metadata.gz: e80dbf6367d3f4b5a829a3bbeb35f6176fb1a205b2ce795b21e61210e083b9d999b01c486b860552cffeccfd036a31330aab651fc5a8463ce3f2767c3f55f153
7
- data.tar.gz: 1c4433c99c886420ef7015b9d65771b01b4bc908f9b3885a104dbf41beaf345092dfa1cf57ec51b9e84f065c6dab6b8ec6be47b5667995f0ad7fc1f545c7e2d1
6
+ metadata.gz: ddcdb7dadd6bc97e2b15c7de0c25835a0cd7d2f9fb87fc7ddf570733a9e0642153020c3186a3854d2cdbe45ea0338b7746833dbea3a2cb0e394c4e43f064dc07
7
+ data.tar.gz: f615d024ba608c5c4286b21067c907cdc6d03863663d33e0d504abac1dfb5b42771ac6b97b8a94d73f4052a1e532148432b74970f8a63c630d81e9fd2e15a317
data/Gemfile CHANGED
@@ -5,4 +5,5 @@ gemspec
5
5
 
6
6
  group :development do
7
7
  gem 'pry'
8
+ gem 'pry-byebug'
8
9
  end
data/README.md CHANGED
@@ -62,15 +62,34 @@ If you omit the parameter, a link won't be added.
62
62
 
63
63
  ## Usage
64
64
 
65
- The gem uses the following regex to detect a reference to a card:
65
+ The commit-message parser looks for the following keywords:
66
66
 
67
- /((case|card|close|fix)e?s? \D?([0-9]+))/i
67
+ * DONE_KEYWORDS:
68
+ * close
69
+ * fix
70
+ * IN_PROGRESS_KEYWORDS:
71
+ * ref
72
+ * reference
73
+ * case
74
+ * issue
75
+ * card
68
76
 
69
- So an example commit message might be:
77
+ For DONE_KEYWORDS, the card is moved to the list with id `LIST_ID_DONE`, while for IN_PROGRESS_KEYWORDS it is moved to the list with id `LIST_ID_IN_PROGRESS`.
70
78
 
71
- Added that awesome feature closes #42
79
+ After it has found a keyword, the parser then looks for space, comma or semi-colon separated lists of (hash-prefixed) ids, e.g.:
80
+
81
+ closes #1
82
+ closes #1 #2 #3
83
+ closes #1, #2, #3
84
+ closes #1, #2 and #3
85
+ closes #1, #2, and #3
86
+ closes #1, #2 & #3
87
+ closes #1, #2, & #3
88
+
89
+ So a typical commit message might be:
90
+
91
+ Added that awesome feature, refs #42 and closes #1, #2 and #3.
72
92
 
73
- For the 'case' and 'card' keywords, the card is moved to the list with id `LIST_ID_IN_PROGRESS`, while for keywords 'close' and 'fix', the card is moved to the list with id `LIST_ID_DONE` .
74
93
 
75
94
  ## Contributing
76
95
 
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
23
24
 
24
25
  spec.add_runtime_dependency 'json'
25
26
  spec.add_runtime_dependency "git", "~> 1.2"
@@ -1,3 +1,3 @@
1
1
  module GitTrelloPostCommit
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -5,6 +5,73 @@ require "git"
5
5
 
6
6
  module GitTrelloPostCommit
7
7
 
8
+ DONE_KEYWORDS = [:close, :fix]
9
+ IN_PROGRESS_KEYWORDS = [:ref, :case, :issue, :card]
10
+
11
+ KEYWORD_REGEX = /((ref)(?:erence)?s?|(case)s?|(issue)s?|(card)s?|(close)s?|(fix)(?:es)?)/i
12
+ ID_REGEX = /\#(?:\d+)/
13
+ ID_LIST_REGEX = /\s*((?:#{ID_REGEX}(?:[,;]?\s+(?:and|\&)|[,;])?\s*)+)/i
14
+ REF_REGEX = /#{KEYWORD_REGEX}\s+#{ID_LIST_REGEX}/
15
+
16
+ ID_CAPTURE_REGEX = /\#(\d+)/
17
+
18
+ class MessageParser
19
+
20
+ def initialize(message)
21
+ @message = message
22
+ end
23
+
24
+ def instructions
25
+ @instructions ||= parse_instructions
26
+ end
27
+
28
+ def parse_instructions
29
+ raw_matches = get_raw_matches
30
+ matches = extract_instructions(raw_matches)
31
+ normalize_matches(matches)
32
+ end
33
+
34
+ def get_raw_matches
35
+ @message.scan(REF_REGEX).map do |match|
36
+ match.compact[1..-1]
37
+ end
38
+ end
39
+
40
+ def categorize_keyword(keyword)
41
+ if DONE_KEYWORDS.include?(keyword) then :done
42
+ elsif IN_PROGRESS_KEYWORDS.include?(keyword) then :in_progress
43
+ end
44
+ end
45
+
46
+ def extract_instructions(raw_matches)
47
+ raw_matches.reduce(Hash.new { |hash, key| hash[key] = [] }) do |matches, raw_match|
48
+ keyword = raw_match.first.downcase.to_sym
49
+ id_list = raw_match.last
50
+ if keyword and id_list
51
+ ids = id_list.scan(ID_CAPTURE_REGEX).flatten.map(&:to_i).select { |n| n>0 }
52
+ ids.each do |id|
53
+ matches[id] << keyword
54
+ end
55
+ end
56
+ matches
57
+ end
58
+ end
59
+
60
+ def normalize_matches(matches)
61
+ matches.reduce({}) do |norm_matches, (card_id, keywords)|
62
+ keywords.uniq!
63
+ categories = keywords.map { |kw| categorize_keyword(kw) }.compact.uniq
64
+ if categories.length > 1 and categories.include?(:done)
65
+ norm_matches[card_id] = :done
66
+ elsif categories.length == 1
67
+ norm_matches[card_id] = categories.first
68
+ end
69
+ norm_matches
70
+ end
71
+ end
72
+
73
+ end
74
+
8
75
  class Hook
9
76
 
10
77
  def initialize(config)
@@ -26,41 +93,41 @@ module GitTrelloPostCommit
26
93
  commit = @repo.gcommit('HEAD')
27
94
  new_sha = commit.sha
28
95
 
29
- # Figure out the card short id
30
- match = commit.message.match(/((case|card|close|fix)e?s? \D?([0-9]+))/i)
31
- return unless match and match[3].to_i > 0
96
+ parser = MessageParser.new(commit.message)
32
97
 
33
- puts "Trello: Commenting on card ##{match[3].to_i}"
98
+ parser.instructions.each do |card_id, action|
34
99
 
35
- results = @http.get_card(@board_id, match[3].to_i)
36
- unless results
37
- puts "Trello: Cannot find card matching ID #{match[3]}"
38
- return
39
- end
40
- results = JSON.parse(results)
100
+ puts "Trello: Commenting on card ##{card_id}"
41
101
 
42
- # Determine the action to take
43
- target_list_id = ""
44
- target_list_id = case match[2].downcase
45
- when "case", "card" then @list_id_in_progress
46
- when "close", "fix" then @list_id_done
47
- end
48
-
49
- # Add the commit comment
50
- message = "#{commit.author.name}:\n#{commit.message}"
51
- message << "\n\n#{@commit_url_prefix}#{new_sha}" unless @commit_url_prefix.nil?
52
- message.gsub!(match[1], "")
53
- message.gsub!(/\(\)$/, "")
54
- message.gsub!(/Signed-off-by: (.*) <(.*)>/,"")
55
- @http.add_comment(results["id"], message)
56
-
57
- unless target_list_id == ""
58
- to_update = {}
59
- unless results["idList"] == target_list_id
60
- puts "Trello: Moving card ##{match[3].to_i} to list #{target_list_id}"
61
- to_update[:idList] = target_list_id
62
- @http.update_card(results["id"], to_update)
102
+ results = @http.get_card(@board_id, card_id)
103
+ unless results
104
+ puts "Trello: Cannot find card matching ID #{card_id}"
105
+ next
106
+ end
107
+ results = JSON.parse(results)
108
+
109
+ # Determine the action to take
110
+ target_list_id = case action
111
+ when :in_progress then @list_id_in_progress
112
+ when :done then @list_id_done
113
+ end
114
+
115
+ # Add the commit comment
116
+ message = "#{commit.author.name}:\n#{commit.message}"
117
+ message << "\n\n#{@commit_url_prefix}#{new_sha}" unless @commit_url_prefix.nil?
118
+ message.gsub!(/\(\)$/, "")
119
+ message.gsub!(/Signed-off-by: (.*) <(.*)>/,"")
120
+ @http.add_comment(results["id"], message)
121
+
122
+ if target_list_id
123
+ to_update = {}
124
+ unless results["idList"] == target_list_id
125
+ puts "Trello: Moving card ##{card_id} to list #{target_list_id}"
126
+ to_update[:idList] = target_list_id
127
+ @http.update_card(results["id"], to_update)
128
+ end
63
129
  end
130
+
64
131
  end
65
132
 
66
133
  end
@@ -0,0 +1,72 @@
1
+ require 'rspec'
2
+ require 'pry'
3
+ require 'git_trello_post_commit'
4
+
5
+ module GitTrelloPostCommit
6
+
7
+ describe MessageParser do
8
+ it "parses single instructions at the end of the message" do
9
+ parser = MessageParser.new("fixed that thing, closes #99")
10
+ expect(parser.instructions).to eq({99 => :done})
11
+ end
12
+
13
+ it "parses single instructions in the middle of a message" do
14
+ parser = MessageParser.new("fixed that thing, closes #99, blah, blah, blah")
15
+ expect(parser.instructions).to eq({99 => :done})
16
+ end
17
+
18
+ it "parses multiple distinct references" do
19
+ parser = MessageParser.new("fixed that thing, closes #99, refs #100")
20
+ expect(parser.instructions).to eq({99 => :done, 100 => :in_progress})
21
+ end
22
+
23
+ it "parses a space separated list of ids for a single action keyword" do
24
+ parser = MessageParser.new("fixed that thing, closes #99 #100 #101")
25
+ expect(parser.instructions).to eq({99 => :done, 100 => :done, 101 => :done})
26
+ end
27
+
28
+ it "parses a csv list of ids for a single action keyword" do
29
+ parser = MessageParser.new("fixed that thing, closes #99, #100, #101")
30
+ expect(parser.instructions).to eq({99 => :done, 100 => :done, 101 => :done})
31
+ end
32
+
33
+ it "parses a csv list of ids (ending with an 'and') for a single action keyword" do
34
+ parser = MessageParser.new("fixed that thing, closes #99, #100 and #101")
35
+ expect(parser.instructions).to eq({99 => :done, 100 => :done, 101 => :done})
36
+ end
37
+
38
+ it "parses a csv list of ids (ending with an '&') for a single action keyword" do
39
+ parser = MessageParser.new("fixed that thing, closes #99, #100 & #101")
40
+ expect(parser.instructions).to eq({99 => :done, 100 => :done, 101 => :done})
41
+ end
42
+
43
+ it "parses a csv list of ids (ending with an ', and') for a single action keyword" do
44
+ parser = MessageParser.new("fixed that thing, closes #99, #100, and #101")
45
+ expect(parser.instructions).to eq({99 => :done, 100 => :done, 101 => :done})
46
+ end
47
+
48
+ it "parses multiple lists of ids for a single action keyword" do
49
+ parser = MessageParser.new("fixed that thing, closes #99, #100 & #101 and refs #1 & #2")
50
+ expect(parser.instructions).to eq({
51
+ 99 => :done, 100 => :done, 101 => :done,
52
+ 1 => :in_progress, 2 => :in_progress
53
+ })
54
+ end
55
+
56
+ it "ignores duplicate instructions" do
57
+ parser = MessageParser.new("fixed that thing on card #99, refs #99")
58
+ expect(parser.instructions).to eq({99 => :in_progress})
59
+ end
60
+
61
+ it "ignores duplicate instructions give in a list" do
62
+ parser = MessageParser.new("fixed the things on cards #99 and #100, refs #99, #100")
63
+ expect(parser.instructions).to eq({99 => :in_progress, 100 => :in_progress})
64
+ end
65
+
66
+ it "ignores conflicting instructions, favouring :done over :in_progress" do
67
+ parser = MessageParser.new("fixed that thing on card #99, closes #99")
68
+ expect(parser.instructions).to eq({99 => :done})
69
+ end
70
+ end
71
+
72
+ end
metadata CHANGED
@@ -1,69 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_trello_post_commit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - jmchambers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-18 00:00:00.000000000 Z
11
+ date: 2014-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: json
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - '>='
59
+ - - ">="
46
60
  - !ruby/object:Gem::Version
47
61
  version: '0'
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - '>='
66
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: git
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - ~>
73
+ - - "~>"
60
74
  - !ruby/object:Gem::Version
61
75
  version: '1.2'
62
76
  type: :runtime
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - ~>
80
+ - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '1.2'
69
83
  description: 'This gem can be used in a post-commit hook in any Git repository to
@@ -76,7 +90,7 @@ executables: []
76
90
  extensions: []
77
91
  extra_rdoc_files: []
78
92
  files:
79
- - .gitignore
93
+ - ".gitignore"
80
94
  - Gemfile
81
95
  - LICENSE.txt
82
96
  - README.md
@@ -85,6 +99,7 @@ files:
85
99
  - lib/git_trello_post_commit.rb
86
100
  - lib/git_trello_post_commit/trello-http.rb
87
101
  - lib/git_trello_post_commit/version.rb
102
+ - spec/message_parser_spec.rb
88
103
  homepage: ''
89
104
  licenses:
90
105
  - MIT
@@ -95,18 +110,20 @@ require_paths:
95
110
  - lib
96
111
  required_ruby_version: !ruby/object:Gem::Requirement
97
112
  requirements:
98
- - - '>='
113
+ - - ">="
99
114
  - !ruby/object:Gem::Version
100
115
  version: '0'
101
116
  required_rubygems_version: !ruby/object:Gem::Requirement
102
117
  requirements:
103
- - - '>='
118
+ - - ">="
104
119
  - !ruby/object:Gem::Version
105
120
  version: '0'
106
121
  requirements: []
107
122
  rubyforge_project:
108
- rubygems_version: 2.1.10
123
+ rubygems_version: 2.2.2
109
124
  signing_key:
110
125
  specification_version: 4
111
126
  summary: Update Trello cards with git commit messages.
112
- test_files: []
127
+ test_files:
128
+ - spec/message_parser_spec.rb
129
+ has_rdoc: