jenkins_pivotal 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|