jenkins_pivotal 0.1.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 +17 -0
- data/Gemfile +9 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +1 -0
- data/bin/jenkins_pivotal +8 -0
- data/jenkins_pivotal.gemspec +27 -0
- data/lib/jenkins_pivotal/agent.rb +156 -0
- data/lib/jenkins_pivotal/changelog_parser.rb +64 -0
- data/lib/jenkins_pivotal/cli.rb +41 -0
- data/lib/jenkins_pivotal/client.rb +58 -0
- data/lib/jenkins_pivotal/version.rb +3 -0
- data/lib/jenkins_pivotal.rb +8 -0
- data/spec/fixtures/changelog.xml +53 -0
- data/spec/fixtures/example-message +1 -0
- data/spec/fixtures/single-entry +10 -0
- data/spec/lib/jenkins_pivotal/agent_spec.rb +149 -0
- data/spec/lib/jenkins_pivotal/changelog_parser_spec.rb +24 -0
- data/spec/lib/jenkins_pivotal/cli_spec.rb +29 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/fixtures.rb +8 -0
- metadata +145 -0
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
data/Gemfile
ADDED
data/Guardfile
ADDED
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"
|
data/bin/jenkins_pivotal
ADDED
@@ -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,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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|
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
|