jenkins_pivotal 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f4aa6f4a314a7e6d757565852e0d2dfc4bbf4756
4
+ data.tar.gz: 53d0944baf85bb5664371dc986af6e9b0e4ace48
5
+ SHA512:
6
+ metadata.gz: f64f207f3d23aa36786248f524fcd90978352ecd38eb9586dd764ee7205ad4585656e337d1b9db52abadb2a5772ec58e874d9c5da19a3b92e11e6fbcf4a09f82
7
+ data.tar.gz: cbe639782a2b45a070362af2af3a5177d1a4c220f8a7bd8eb09cc4b6d29e5e60359daabe5ebc271bc9ea984cd43f42a4f05e6cbb5cc61348171a22a2bad526dd
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jenkins_pivotal.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'guard'
8
+ gem 'guard-rspec'
9
+ end
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Mike Wyatt
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Jenkins + PivotalTracker
2
+
3
+ Much like jenkins_tracker, only uses the proper /source_commits endpoint
4
+ and will set the owner to an "acceptor" when an issues is marked as
5
+ delivered.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ gem install jenkins_pivotal
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ In Jenkins, add a post build step like:
16
+
17
+ ```
18
+ jenkins_pivotal --token a1b2c3 --project 1234 --acceptor-token d4e5f6
19
+ ```
20
+
21
+ Help output is as follows.
22
+
23
+ ```
24
+ Usage: bin/jenkins_pivotal [options...]
25
+ -t, --token Tracker API token.
26
+ -p, --project Tracker Project ID.
27
+ -m, --message Message to add.
28
+ -f, --file Read message from file.
29
+ -u, --url URL to browse commit.
30
+ -a, --acceptor-token Tracker token of acceptor.
31
+ -v, --version Display version information.
32
+ -h, --help Display this help message.
33
+ ```
34
+
35
+ - `--url`: Something like `http://example.com/%s`. It will be formatted
36
+ with the SHA1 of the accompanying commit.
37
+ - `--mesage`/`--file`: Add this message above the commit message in
38
+ Pivotal. This is formatted with the ENV, so with EnvInject you can do
39
+ something akin to `--message "This issue has been deployed to
40
+ %{STAGING_URL}"`
41
+
42
+ Only `--token` and `--project` are required. Use `--acceptor-token` if
43
+ you would like to change the owner of issues as they are marked for
44
+ delivery.
45
+
46
+ ## Contributing
47
+
48
+ 1. Fork it ( http://github.com/mikew/jenkins_pivotal/fork )
49
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
50
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
51
+ 4. Push to the branch (`git push origin my-new-feature`)
52
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path '../../lib', __FILE__
4
+ $:.unshift(root) unless $:.include?(root)
5
+
6
+ require 'jenkins_pivotal'
7
+
8
+ JenkinsPivotal::Cli.new(ARGV).run!
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jenkins_pivotal/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jenkins_pivotal"
8
+ spec.version = JenkinsPivotal::VERSION
9
+ spec.authors = ["Mike Wyatt"]
10
+ spec.email = ["wyatt.mike@gmail.com"]
11
+ spec.summary = %q{Jenkins git changelog -> Pivotal Tracker}
12
+ spec.description = %q{Jenkins git changelog -> Pivotal Tracker}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "rest-client", "~> 1.6"
22
+ spec.add_dependency "slop", "~> 3.4"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.5"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ end
@@ -0,0 +1,156 @@
1
+ module JenkinsPivotal
2
+ class Agent
3
+ attr_reader :token, :project, :message, :url, :current_entry, :file,
4
+ :acceptor_token
5
+
6
+ def initialize(options)
7
+ @token = options[:token]
8
+ @project = options[:project].to_i
9
+ @message = options[:message]
10
+ @file = options[:file]
11
+ @url = options[:url]
12
+ @acceptor_token = options[:acceptor_token]
13
+ @current_entry = nil
14
+ end
15
+
16
+ def file_contents
17
+ if file
18
+ File.read(file).strip
19
+ end
20
+ end
21
+
22
+ def browser_url
23
+ if url
24
+ url % current_entry.sha1
25
+ end
26
+ end
27
+
28
+ def client
29
+ @_client ||= Client.new token: token, acceptor_token: acceptor_token
30
+ end
31
+
32
+ def message_to_post
33
+ given_message = nil
34
+
35
+ if message
36
+ given_message = message
37
+ end
38
+
39
+ if file
40
+ given_message = file_contents
41
+ end
42
+
43
+ if given_message
44
+ formatted = given_message % message_variables
45
+ return "#{formatted}\n\n#{current_entry.message}"
46
+ end
47
+
48
+ current_entry.message
49
+ end
50
+
51
+ def message_variables
52
+ env_variables.inject({}) do |memo, (k, v)|
53
+ memo[k.to_sym] = v
54
+ memo
55
+ end
56
+ end
57
+
58
+ def should_deliver(msg)
59
+ ret = []
60
+ refs = msg.scan /\[((?:.*?)([#0-9 ]+)(?:.*?))\]/
61
+
62
+ refs.each do |group|
63
+ if group[0].downcase.include? 'deliver'
64
+ ids = group[1].strip.split
65
+ ret.concat ids.map { |i| i.gsub('#', '').to_i }
66
+ end
67
+ end
68
+
69
+ return ret
70
+ end
71
+
72
+ def run!
73
+ all_entries = []
74
+ changelog_paths.each do |path|
75
+ parser = ChangelogParser.new changelog_path
76
+ all_entries.concat parser.entries
77
+ end
78
+
79
+ all_entries.each do |entry|
80
+ @current_entry = entry
81
+
82
+ payload = {
83
+ source_commit: {
84
+ url: browser_url,
85
+ message: message_to_post,
86
+ author: current_entry.author_name,
87
+ commit_id: current_entry.sha1
88
+ }
89
+ }
90
+
91
+ client.post_source_commits payload
92
+
93
+ should_deliver(current_entry.message).each do |story_id|
94
+ client.deliver_to_acceptor project, story_id
95
+ end
96
+ end
97
+ end
98
+
99
+ def changelog_paths
100
+ # TODO this should be extracted into ChangelogGatherer or something
101
+ if ENV['CHANGELOG_PATH']
102
+ return [ ENV['CHANGELOG_PATH'] ]
103
+ end
104
+
105
+ start_from = 1
106
+ default_changelog = File.join env_variables['JENKINS_HOME'],
107
+ 'jobs', env_variables['JOB_NAME'],
108
+ 'builds', env_variables['BUILD_NUMBER'],
109
+ 'changelog.xml'
110
+
111
+ # If it's the first build, there's nothing to gather.
112
+ if env_variables['BUILD_NUMBER'] == '1'
113
+ return [ default_changelog ]
114
+ end
115
+
116
+ last_success = File.join env_variables['JENKINS_HOME'],
117
+ 'jobs', env_variables['JOB_NAME'],
118
+ 'builds', 'lastSuccessfulBuild'
119
+
120
+ last_success_num = File.readlink last_success
121
+ if last_success_num != '-1'
122
+ # If the lastSuccessfulBuild was the previous build then the
123
+ # changelog will already be adequate.
124
+ if last_success_num.to_i == env_variables['BUILD_NUMBER'].to_i - 1
125
+ return [ default_changelog ]
126
+ else
127
+ start_from = last_success_num.to_i + 1
128
+ end
129
+ end
130
+
131
+ start_from.upto(env_variables['BUILD_NUMBER'].to_i).map do |i|
132
+ File.join env_variables['JENKINS_HOME'],
133
+ 'jobs', env_variables['JOB_NAME'],
134
+ 'builds', i.to_s,
135
+ 'changelog.xml'
136
+ end
137
+ end
138
+
139
+ private
140
+
141
+ def env_variables
142
+ ENV
143
+ end
144
+
145
+ def changelog_path
146
+ if ENV['CHANGELOG_PATH']
147
+ return ENV['CHANGELOG_PATH']
148
+ end
149
+
150
+ File.join ENV['JENKINS_HOME'],
151
+ 'jobs', ENV['JOB_NAME'],
152
+ 'builds', ENV['BUILD_NUMBER'],
153
+ 'changelog.xml'
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,64 @@
1
+ module JenkinsPivotal
2
+ class ChangelogParser
3
+ attr_reader :entries, :data
4
+
5
+ def initialize(path)
6
+ @data = ''
7
+ @entries = []
8
+
9
+ if File.exists? path
10
+ @data = File.read path
11
+ load_entries
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def load_entries
18
+ blocks = @data.split /^(commit [a-f0-9]{40})/
19
+
20
+ # If the first line is `commit ...`, the first item of the array will
21
+ # be an empty string.
22
+ if '' == blocks[0]
23
+ blocks.shift
24
+ end
25
+
26
+ # The first line may be something else entirely, like:
27
+ # Changes in branch origin/master, between ...
28
+ if !blocks[0].start_with? 'commit'
29
+ blocks.shift
30
+ end
31
+
32
+ blocks.each_slice(2) do |block|
33
+ @entries.push ChangelogEntry.new(block[0] + block[1])
34
+ end
35
+ end
36
+ end
37
+
38
+ class ChangelogEntry
39
+ attr_reader :author, :author_name, :author_email,
40
+ :committer, :committer_name, :committer_email,
41
+ :sha1, :tree, :parent,
42
+ :message
43
+
44
+ def initialize(data)
45
+ @data = data
46
+ @message = data.split("\n\n")[1].strip
47
+ @sha1 = first_from_scan /^commit ([a-f0-9]{40})/
48
+ @tree = first_from_scan /^tree ([a-f0-9]{40})/
49
+ @parent = first_from_scan /^parent ([a-f0-9]{40})/
50
+ @author = first_from_scan /^author ((.+?) <(.+?)>)/
51
+ @author_name = first_from_scan /^author (.+?) </
52
+ @author_email = first_from_scan /^author .+? <(.+?)>/
53
+ @committer = first_from_scan /^committer ((.+?) <(.+?)>)/
54
+ @committer_name = first_from_scan /^committer (.+?) </
55
+ @committer_email = first_from_scan /^committer .+? <(.+?)>/
56
+ end
57
+
58
+ private
59
+
60
+ def first_from_scan(matcher)
61
+ $1.strip if @data =~ matcher
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,41 @@
1
+ require 'slop'
2
+
3
+ module JenkinsPivotal
4
+ class Cli
5
+ attr_reader :options
6
+
7
+ def initialize(items = ARGV)
8
+ @options = Slop.parse(items, help: true) do
9
+ banner "Usage: #{$0} [options...]"
10
+
11
+ on 't', 'token=', 'Tracker API token.'
12
+ on 'p', 'project=', 'Tracker Project ID.', as: :integer
13
+ on 'm', 'message=', 'Message to add.'
14
+ on 'f', 'file=', 'Read message from file.'
15
+ on 'u', 'url=', 'URL to browse commit.'
16
+ on 'a', 'acceptor-token=', 'Tracker token of acceptor.'
17
+
18
+ on 'v', 'version', 'Display version information.' do
19
+ puts "#{$0} #{JenkinsPivotal::VERSION}"
20
+ exit 0
21
+ end
22
+ end
23
+ end
24
+
25
+ def run!
26
+ unless options.token? && options.project?
27
+ puts @options
28
+ exit 1
29
+ end
30
+
31
+ Agent.new(
32
+ token: options[:token],
33
+ project: options[:project],
34
+ message: options[:message],
35
+ file: options[:file],
36
+ url: options[:url],
37
+ acceptor_token: options[:'acceptor-token']
38
+ ).run!
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,58 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+
4
+ module JenkinsPivotal
5
+ class Client
6
+ attr_reader :connection
7
+
8
+ def initialize(options)
9
+ @options = options
10
+ @connection = build_connection options[:token]
11
+ load_acceptor if options[:acceptor_token]
12
+ end
13
+
14
+ def load_acceptor
15
+ acceptor_conn = build_connection @options[:acceptor_token]
16
+ json = JSON.parse acceptor_conn['/me'].get
17
+ @acceptor_id = json['id']
18
+ @acceptor_name = json['name']
19
+ end
20
+
21
+ def post_source_commits(payload)
22
+ begin
23
+ connection['/source_commits'].post payload.to_json
24
+ rescue => e
25
+ puts e.message
26
+ puts e.http_body
27
+ end
28
+ end
29
+
30
+ def deliver_to_acceptor(project, story_id)
31
+ return unless @acceptor_id
32
+
33
+ begin
34
+ endpoint = "projects/#{project}/stories/#{story_id}"
35
+ payload = { owned_by_id: @acceptor_id }
36
+ connection[endpoint].put payload.to_json
37
+ rescue => e
38
+ puts e.message
39
+ puts e.http_body
40
+ end
41
+ end
42
+
43
+ def api_url
44
+ 'https://www.pivotaltracker.com/services/v5'
45
+ end
46
+
47
+ private
48
+
49
+ def build_connection(token)
50
+ headers = {
51
+ 'X-TrackerToken' => token,
52
+ 'Content-Type' => 'application/json'
53
+ }
54
+
55
+ RestClient::Resource.new api_url, headers: headers
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module JenkinsPivotal
2
+ VERSION = '0.1.1'
3
+ end
@@ -0,0 +1,8 @@
1
+ require 'jenkins_pivotal/agent'
2
+ require 'jenkins_pivotal/changelog_parser'
3
+ require 'jenkins_pivotal/cli'
4
+ require 'jenkins_pivotal/client'
5
+ require 'jenkins_pivotal/version'
6
+
7
+ module JenkinsPivotal
8
+ end
@@ -0,0 +1,53 @@
1
+ commit 9682485f5b8c5078548a4094ceab789a48150aa8
2
+ tree f338db9d1ad3a1518f864576f04d1247a908a6bb
3
+ parent d9ddf907ed650d0ef30f2d4cf7610024eb3dd0d0
4
+ author Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
5
+ committer Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
6
+
7
+ proper user_is_omniscient logic
8
+
9
+ :100644 100644 b49e6da4bc7a90e0bb6a819f4670f55d9fde6501 e3c4b32bba5c005bd571cfa45cca59fa42f29faa M dashboard/views.py
10
+
11
+ commit f56e6f4bc8abeb01d3ef31eaab0aa137c8aad970
12
+ tree 314c398b0db343ca960ebf3a79d547975cb3fa25
13
+ parent cf747b094e18c2055cff517f8b8cd7f06691293c
14
+ author Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
15
+ committer Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
16
+
17
+ Use global showDialog function on calendar
18
+
19
+ :100644 100644 425cec2a745b01ada9618b6262cea1597c4fc434 d2decc09a6f95283f2565f4ee6b6f3720e2751f5 M tcecalendar/static/js/calendar.js
20
+
21
+ commit d9ddf907ed650d0ef30f2d4cf7610024eb3dd0d0
22
+ tree a632c0cbbefb4250433e9b3fe68ce93f10fa7c71
23
+ parent 4bc2782e5896e37947e3bd2273b6a5cfbbd9169d
24
+ author Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
25
+ committer Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
26
+
27
+ show completed tasks on dashboard, omniscient roles see all tasks
28
+
29
+ :100644 100644 ebb22924da0183007bb73600a262f22381b520df b49e6da4bc7a90e0bb6a819f4670f55d9fde6501 M dashboard/views.py
30
+
31
+ commit 4bc2782e5896e37947e3bd2273b6a5cfbbd9169d
32
+ tree ec13b8b32fe46a54846cbddc928eaa0907a93e6d
33
+ parent 928c51bfb5508846240fdbf2f6df650278d62baa
34
+ author Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
35
+ committer Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
36
+
37
+ rebuild stylesheets
38
+
39
+ :100644 100644 a37962188ac93f1beba47e1e37838741c6460ebf 16e597cae082634d6abd4f0b4e489fe007a29f8d M frontend/static/assets/stylesheets/libs/mobile/learning-centre.css
40
+ :100644 100644 bfc39b983f7401594e1e61e76591fa9558113929 a9f2be7fcff4df92a3cef0b8cf94fb8d3f693ee2 M frontend/static/assets/stylesheets/libs/mobile/teachers-lounge.css
41
+ :100644 100644 00b41fa6758ddeed334fba53779edb0d3331c192 db6f3c0a2ff9bee71cabe7acbddba5ca92e3df94 M frontend/static/assets/stylesheets/mobile_TCE.css
42
+ :100644 100644 3e9d93f235b2be103aa17e8e29f848d2309b7e18 91b1070b37a4eb46e85054177d69adee439b80bf M frontend/static/assets/stylesheets/screen-TCE.css
43
+
44
+ commit e26a7acda7bcdf428ad098e6b4eb9b66b7759bc6
45
+ tree 666900a05c95a597b5eb1504d9c7baea54ec833e
46
+ parent d4a6136ac66041ea5729557a1511df23bf6c89e3
47
+ author Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
48
+ committer Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
49
+
50
+ Fix for `incompatible character encodings: ASCII-8BIT and UTF-8`, maybe
51
+
52
+ :100644 100644 a2c5e5813c7a91177bdb0218af463c5baca4072e 868c0ea25a6ee98d61291e95897a1939f12f14a8 M frontend/sass/config-dev.rb
53
+ :100644 100644 95507498a0cb62ef5f469aaa16bdfc33580b8e47 7f9ab18a069fb37e41a42e86b09610a020f0978f M frontend/sass/config.rb
@@ -0,0 +1 @@
1
+ %{foo}
@@ -0,0 +1,10 @@
1
+ commit 9682485f5b8c5078548a4094ceab789a48150aa8
2
+ tree f338db9d1ad3a1518f864576f04d1247a908a6bb
3
+ parent d9ddf907ed650d0ef30f2d4cf7610024eb3dd0d0
4
+ author Mike Wyatt <wyatt.mike@gmail.com> 1387468320 -0400
5
+ committer Joe Smith <joe.smith@gmail.com> 1387468320 -0400
6
+
7
+ proper user_is_omniscient logic
8
+
9
+ :100644 100644 b49e6da4bc7a90e0bb6a819f4670f55d9fde6501 e3c4b32bba5c005bd571cfa45cca59fa42f29faa M dashboard/views.py
10
+
@@ -0,0 +1,149 @@
1
+ require 'spec_helper'
2
+ require 'fakefs/spec_helpers'
3
+
4
+ describe JenkinsPivotal::Agent do
5
+ subject do
6
+ described_class.new(
7
+ token: 'asdf',
8
+ project: '1234',
9
+ message: '%{foo}',
10
+ url: 'http://example.com/%s',
11
+ file: fixture_path('example-message')
12
+ )
13
+ end
14
+
15
+ let(:entry) { JenkinsPivotal::ChangelogEntry.new read_fixture('single-entry') }
16
+
17
+ before do
18
+ subject.stub(:current_entry).and_return entry
19
+ end
20
+
21
+ its(:token) { should == 'asdf' }
22
+ its(:project) { should == 1234 }
23
+ its(:message) { should == '%{foo}' }
24
+ its(:file_contents) { should == read_fixture('example-message').strip }
25
+ its(:browser_url) { should == subject.url % entry.sha1 }
26
+
27
+ describe 'with messages' do
28
+ before do
29
+ subject.stub(:env_variables).and_return 'foo' => 'bar'
30
+ end
31
+
32
+ it 'converts strings to symbols in message_variables' do
33
+ subject.message_variables[:foo].should == 'bar'
34
+ end
35
+
36
+ it 'formats message with ENV' do
37
+ subject.stub(:file).and_return nil
38
+ subject.message_to_post.should == "bar\n\n#{entry.message}"
39
+ end
40
+
41
+ it 'formats file with ENV' do
42
+ subject.stub(:message).and_return nil
43
+ subject.message_to_post.should == "bar\n\n#{entry.message}"
44
+ end
45
+
46
+ it 'simply posts the commit message when neither exist' do
47
+ subject.stub(:file).and_return nil
48
+ subject.stub(:message).and_return nil
49
+ subject.message_to_post.should == entry.message
50
+ end
51
+ end
52
+
53
+ describe 'with deliveries' do
54
+ it 'can tell when an issue is delivered' do
55
+ single = '[delivers #123]'
56
+ multiple = '[#123 delivered] [deliver #234]'
57
+ complex = '[delivers #123 #234] [#345]'
58
+ none = '[#123] not delivered'
59
+
60
+ subject.should_deliver(single).should == [123]
61
+ subject.should_deliver(multiple).should == [123, 234]
62
+ subject.should_deliver(complex).should == [123, 234]
63
+ subject.should_deliver(none).should == []
64
+ end
65
+ end
66
+
67
+ describe 'gathering changelogs' do
68
+ let(:env) do
69
+ {
70
+ 'JENKINS_HOME' => fixture_path('structures')
71
+ }
72
+ end
73
+
74
+ it 'returns the default changelog on first build' do
75
+ stubbed_env = {
76
+ 'BUILD_NUMBER' => '1',
77
+ 'JOB_NAME' => 'first-run'
78
+ }.merge env
79
+
80
+ expected = [ File.join(stubbed_env['JENKINS_HOME'],
81
+ 'jobs', stubbed_env['JOB_NAME'],
82
+ 'builds', stubbed_env['BUILD_NUMBER'],
83
+ 'changelog.xml'
84
+ ) ]
85
+
86
+ subject.stub(:env_variables).and_return stubbed_env
87
+ subject.changelog_paths.should == expected
88
+ end
89
+
90
+ it 'starts from 1 when the lastSuccessfulBuild is -1' do
91
+ stubbed_env = {
92
+ 'BUILD_NUMBER' => '3',
93
+ 'JOB_NAME' => 'cloudy'
94
+ }.merge env
95
+
96
+ last_success = File.join(stubbed_env['JENKINS_HOME'],
97
+ 'jobs', stubbed_env['JOB_NAME'],
98
+ 'builds', 'lastSuccessfulBuild')
99
+ File.should_receive(:readlink, with: last_success).and_return '-1'
100
+
101
+ expected = [
102
+ File.join(stubbed_env['JENKINS_HOME'],
103
+ 'jobs', stubbed_env['JOB_NAME'],
104
+ 'builds', '1',
105
+ 'changelog.xml'),
106
+
107
+ File.join(stubbed_env['JENKINS_HOME'],
108
+ 'jobs', stubbed_env['JOB_NAME'],
109
+ 'builds', '2',
110
+ 'changelog.xml'),
111
+
112
+ File.join(stubbed_env['JENKINS_HOME'],
113
+ 'jobs', stubbed_env['JOB_NAME'],
114
+ 'builds', stubbed_env['BUILD_NUMBER'],
115
+ 'changelog.xml'),
116
+ ]
117
+
118
+ subject.stub(:env_variables).and_return stubbed_env
119
+ subject.changelog_paths.should == expected
120
+ end
121
+
122
+ it 'starts from lastSuccessfulBuild + 1 otherwise' do
123
+ stubbed_env = {
124
+ 'BUILD_NUMBER' => '5',
125
+ 'JOB_NAME' => 'cloudy'
126
+ }.merge env
127
+
128
+ last_success = File.join(stubbed_env['JENKINS_HOME'],
129
+ 'jobs', stubbed_env['JOB_NAME'],
130
+ 'builds', 'lastSuccessfulBuild')
131
+ File.should_receive(:readlink, with: last_success).and_return '3'
132
+
133
+ expected = [
134
+ File.join(stubbed_env['JENKINS_HOME'],
135
+ 'jobs', stubbed_env['JOB_NAME'],
136
+ 'builds', '4',
137
+ 'changelog.xml'),
138
+
139
+ File.join(stubbed_env['JENKINS_HOME'],
140
+ 'jobs', stubbed_env['JOB_NAME'],
141
+ 'builds', stubbed_env['BUILD_NUMBER'],
142
+ 'changelog.xml'),
143
+ ]
144
+
145
+ subject.stub(:env_variables).and_return stubbed_env
146
+ subject.changelog_paths.should == expected
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe JenkinsPivotal::ChangelogParser do
4
+ subject { described_class.new fixture_path('changelog.xml') }
5
+
6
+ its(:entries) { should be_an Array }
7
+ its(:'entries.length') { should == 5 }
8
+ its(:data) { should == read_fixture('changelog.xml') }
9
+ end
10
+
11
+ describe JenkinsPivotal::ChangelogEntry do
12
+ subject { described_class.new read_fixture('single-entry') }
13
+
14
+ its(:author) { should == 'Mike Wyatt <wyatt.mike@gmail.com>' }
15
+ its(:author_name) { should == 'Mike Wyatt' }
16
+ its(:author_email) { should == 'wyatt.mike@gmail.com' }
17
+ its(:committer) { should == 'Joe Smith <joe.smith@gmail.com>' }
18
+ its(:committer_name) { should == 'Joe Smith' }
19
+ its(:committer_email) { should == 'joe.smith@gmail.com' }
20
+ its(:message) { should == 'proper user_is_omniscient logic' }
21
+ its(:sha1) { should == '9682485f5b8c5078548a4094ceab789a48150aa8' }
22
+ its(:tree) { should == 'f338db9d1ad3a1518f864576f04d1247a908a6bb' }
23
+ its(:parent) { should == 'd9ddf907ed650d0ef30f2d4cf7610024eb3dd0d0' }
24
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe JenkinsPivotal::Cli do
4
+ def try_arg(argument, value)
5
+ args = ["--#{argument}", value.to_s]
6
+ described_class.new(args).options[argument].should == value
7
+ end
8
+
9
+ it 'takes --token' do
10
+ try_arg :token, 'ASDF'
11
+ end
12
+
13
+ it 'takes --project' do
14
+ try_arg :project, 1234
15
+ end
16
+
17
+ it 'takes --message' do
18
+ try_arg :message, 'Message'
19
+ end
20
+
21
+ it 'takes --file' do
22
+ try_arg :file, '/a/b/c'
23
+ end
24
+
25
+ it 'takes --url' do
26
+ try_arg :url, 'http://example.com/%s'
27
+ end
28
+
29
+ end
@@ -0,0 +1,12 @@
1
+ require 'jenkins_pivotal'
2
+
3
+ spec_root = File.expand_path '../', __FILE__
4
+ Dir[File.join(spec_root, 'support/**/*.rb')].each { |f| require f }
5
+
6
+ RSpec.configure do |config|
7
+ config.treat_symbols_as_metadata_keys_with_true_values = true
8
+ config.run_all_when_everything_filtered = true
9
+ config.filter_run :focus
10
+
11
+ config.order = 'random'
12
+ end
@@ -0,0 +1,8 @@
1
+ def read_fixture(filename)
2
+ File.read fixture_path(filename)
3
+ end
4
+
5
+ def fixture_path(filename)
6
+ spec_root = File.expand_path '../../', __FILE__
7
+ File.join spec_root, 'fixtures', filename
8
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jenkins_pivotal
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Mike Wyatt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: slop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '3.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
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: rspec
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
+ description: Jenkins git changelog -> Pivotal Tracker
84
+ email:
85
+ - wyatt.mike@gmail.com
86
+ executables:
87
+ - jenkins_pivotal
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - Gemfile
93
+ - Guardfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - bin/jenkins_pivotal
98
+ - jenkins_pivotal.gemspec
99
+ - lib/jenkins_pivotal.rb
100
+ - lib/jenkins_pivotal/agent.rb
101
+ - lib/jenkins_pivotal/changelog_parser.rb
102
+ - lib/jenkins_pivotal/cli.rb
103
+ - lib/jenkins_pivotal/client.rb
104
+ - lib/jenkins_pivotal/version.rb
105
+ - spec/fixtures/changelog.xml
106
+ - spec/fixtures/example-message
107
+ - spec/fixtures/single-entry
108
+ - spec/lib/jenkins_pivotal/agent_spec.rb
109
+ - spec/lib/jenkins_pivotal/changelog_parser_spec.rb
110
+ - spec/lib/jenkins_pivotal/cli_spec.rb
111
+ - spec/spec_helper.rb
112
+ - spec/support/fixtures.rb
113
+ homepage: ''
114
+ licenses:
115
+ - MIT
116
+ metadata: {}
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubyforge_project:
133
+ rubygems_version: 2.0.14
134
+ signing_key:
135
+ specification_version: 4
136
+ summary: Jenkins git changelog -> Pivotal Tracker
137
+ test_files:
138
+ - spec/fixtures/changelog.xml
139
+ - spec/fixtures/example-message
140
+ - spec/fixtures/single-entry
141
+ - spec/lib/jenkins_pivotal/agent_spec.rb
142
+ - spec/lib/jenkins_pivotal/changelog_parser_spec.rb
143
+ - spec/lib/jenkins_pivotal/cli_spec.rb
144
+ - spec/spec_helper.rb
145
+ - spec/support/fixtures.rb