WTBuildHelpers 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 899f3d4ed4d147d9310a7327e55318e6ec88bc38
4
+ data.tar.gz: 3eae7c5fe00913c91c507972610b0166845a4d46
5
+ SHA512:
6
+ metadata.gz: aec03ba6b56605356742fe8d81c2f322016b63860202e7e8d1b4b5a230a2de855d63263c8c02da24cbb9aff925c88fca07938f32ef448211738eefc6602d9650
7
+ data.tar.gz: 2f2212b2a1c62cc090d51ac58c95a82c972ee3ccb44636a8e4ed212b8cf5d863cbbc78767aac4b679cf679f82143930eed2c3156b7da9075ecaf1a292c2e3c11
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in WTBuildHelpersGem.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 WillowTree
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # WTBuildHelpersGem
2
+
3
+ This is a set of scripts for multiple platforms to help with building and testing tasks
4
+ specific to WillowTree's pipelines and integrations.
5
+
6
+ ### JIRA
7
+
8
+ #### perform_jira_update
9
+ Updates any jira tickets based on the supplied git commit range.
10
+
11
+ Environment Variables
12
+ - JIRA_URL - Base url for JIRA
13
+ - JIRA_USERNAME - Username for accessing JIRA
14
+ - JIRA_PASSWORD - Password for accessing JIRA
15
+ - Supplied by Travis-CI:
16
+ - TRAVIS_COMMIT_RANGE - range of commits to update
17
+ - TRAVIS_BUILD_NUMBER - build number
18
+ - Supplied by TeamCity
19
+ - BUILD_NUMBER - build number
20
+ - TRAMCITY_COMMIT_RANGE - created by teamcity_git_range_fetch
21
+
22
+ Command Line Usage:
23
+ ```bash
24
+ $ wtbuild_jira_update
25
+ ```
26
+
27
+ ### TeamCity
28
+ #### teamcity_git_range_fetch
29
+ Fetches the last good build from the TeamCity server and uses that to produce the a git commit range.
30
+
31
+ Command Line Usage (from TeamCity build step):
32
+ ```bash
33
+ $ wtbuild_teamcity_fetch_git_range "%teamcity.serverUrl%" "%system.teamcity.buildType.id%" "%system.teamcity.auth.userId%" "%system.teamcity.auth.password%"``
34
+ ```
35
+
36
+
37
+ ## Installation
38
+
39
+ Add this line to your application's Gemfile:
40
+
41
+ ```ruby
42
+ gem 'WTBuildHelpersGem'
43
+ ```
44
+
45
+ And then execute:
46
+
47
+ $ bundle
48
+
49
+ Or install it yourself as:
50
+
51
+ $ gem install WTBuildHelpersGem
52
+
53
+ ## Usage
54
+
55
+
56
+
57
+ ## Development
58
+
59
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'WTBuildHelpers/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "WTBuildHelpers"
8
+ spec.summary = "Helpers for performing common WillowTree build tasks and integrations"
9
+ spec.version = WTBuildHelpers::VERSION
10
+ spec.authors = ["WillowTreeApps"]
11
+ spec.email = ["jeff.ward@willowtreeapps.com"]
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
15
+ spec.bindir = "exe"
16
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_runtime_dependency 'OptionParser', '~> 0.5.1'
20
+ spec.add_runtime_dependency 'rest-client', '~> 1.8.0'
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.9"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "WTBuildHelpers"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'WTBuildHelpers'
4
+
5
+ WTBuildHelpers::Jira.perform_jira_update(nil)
@@ -0,0 +1,13 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'WTBuildHelpers'
4
+
5
+ if ARGV.length != 4
6
+ puts "Usage: teamcity_git_range_fetch.rb [TeamCity Url] [TeamCity Build Type Id] [TeamCity User Name] [TeamCity Password]"
7
+ puts "These parameters can be passed from TeamCity with the following line: "
8
+ puts " teamcity_git_range_fetch.rb \"%teamcity.serverUrl%\" \"%system.teamcity.buildType.id%\" \"%system.teamcity.auth.userId%\" \"%system.teamcity.auth.password%\""
9
+
10
+ exit
11
+ end
12
+
13
+ WTBuildHelpers::TeamCity.fetch_commit_range(ARGV[0], ARGV[1], ARGV[2], ARGV[3])
@@ -0,0 +1,3 @@
1
+ module WTBuildHelpers
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,8 @@
1
+ require "WTBuildHelpers/version"
2
+
3
+ require "jira_tasks"
4
+ require "teamcity_git_range_fetch"
5
+
6
+ module WTBuildHelpers
7
+ # Your code goes here...
8
+ end
data/lib/jira_tasks.rb ADDED
@@ -0,0 +1,241 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'pp'
5
+ require 'set'
6
+ require 'rest_client'
7
+ require 'base64'
8
+ require 'json'
9
+
10
+ module WTBuildHelpers
11
+ module Jira
12
+ Options = Struct.new(:commit_range, :site, :username, :password, :build)
13
+
14
+ class JiraInfo
15
+ attr_reader :fixed_in_build_field_id
16
+ attr_reader :build_complete_transition_id
17
+
18
+ attr_reader :site
19
+ attr_reader :base_url
20
+ attr_reader :auth_token
21
+
22
+ def initialize(site, username, password)
23
+ @site = site
24
+ @username = username
25
+ @password = password
26
+
27
+ @auth_token = Base64.encode64("#{username}:#{password}")
28
+ @base_url = File.join(site, '/rest/api/2')
29
+ end
30
+
31
+ def update_fixed_in_build()
32
+ headers = { "Authorization" => "Basic #{@auth_token}" }
33
+
34
+ # Find the Fixed In Build field
35
+ begin
36
+ fields_url = File.join(@base_url, 'field')
37
+ response = RestClient.get(fields_url, headers=headers)
38
+
39
+ fields = JSON.parse(response.body);
40
+ fixed_field = fields.find do |field|
41
+ field["name"] == "Fixed In Build"
42
+ end
43
+
44
+ @fixed_in_build_field_id = fixed_field["id"]
45
+ rescue RestClient::Exception => e
46
+ puts "Error code #{e.response.code} attempting to find Fixed In Build field"
47
+ end
48
+ end
49
+
50
+ def update_build_complete_transition(issue_key)
51
+ headers = { "Authorization" => "Basic #{@auth_token}"}
52
+
53
+ fields_url = File.join(@base_url, 'issue', issue_key, 'transitions')
54
+ begin
55
+ response = RestClient.get(fields_url, headers=headers)
56
+
57
+ response_json = JSON.parse(response.body)
58
+ transitions = response_json["transitions"]
59
+ build_complete_transition = transitions.find do |transition|
60
+ transition["name"] == "Build Complete"
61
+ end
62
+
63
+ if not build_complete_transition.nil?
64
+ @build_complete_transition_id = build_complete_transition["id"]
65
+ end
66
+ rescue RestClient::Exception => e
67
+ puts "Error code #{e.response.code} attempting to find Build Complete transition"
68
+ end
69
+ end
70
+ end
71
+
72
+ class Parser
73
+ def self.parse(options)
74
+ args = Options.new()
75
+
76
+ opt_parser = OptionParser.new do |opts|
77
+ opts.banner = "Usage: jira_tasks.rb [options]"
78
+
79
+ opts.on("-c", "--commits COMMIT_RANGE", "Specify a commit range") do |commit_range|
80
+ args.commit_range = commit_range
81
+ end
82
+
83
+ opts.on("-u", "--username USERNAME", "Specify the user to connecto to JIRA") do |username|
84
+ args.username = username
85
+ end
86
+
87
+ opts.on("-p", "--password PASSWORD", "Specify the password to connect to JIRA") do |password|
88
+ args.password = password
89
+ end
90
+
91
+ opts.on("-s", "--site SITE", "Specify the base location of the JIRA instance") do |site|
92
+ site.slice!("http://")
93
+ site.insert(0, "https://")
94
+ args.site = site
95
+ end
96
+
97
+ opts.on("-b", "--build BUILD", "The build number for which this script is executing") do |build|
98
+ args.build = build
99
+ end
100
+
101
+ opts.on_tail("-h", "--help", "Show this message") do
102
+ puts opts
103
+ exit
104
+ end
105
+ end
106
+
107
+ opt_parser.parse!(options)
108
+ return args
109
+ end
110
+ end
111
+
112
+ def self.find_jira_issues(logs)
113
+ issue_set = Set.new
114
+ logs.each do |log|
115
+ issues = log.scan(/[A-Z][A-Z]+-[1-9][0-9]*/)
116
+ issue_set.merge(issues)
117
+ end
118
+
119
+ return issue_set
120
+ end
121
+
122
+ def self.get_git_history(commit_range)
123
+ happyface = "\u263A".encode('utf-8')
124
+ git_log = `git --no-pager log --format="%B#{happyface}" #{commit_range} `
125
+
126
+ #parse out the log
127
+ logs = git_log.split(happyface)
128
+
129
+ return logs
130
+ end
131
+
132
+ def self.jira_update(jira_info, issues, build)
133
+ jira_url = File.join(jira_info.base_url, 'issue')
134
+
135
+ if jira_info.fixed_in_build_field_id.nil?
136
+ jira_info.update_fixed_in_build
137
+ end
138
+
139
+ # Something's wrong. We're not on our JIRA
140
+ return if jira_info.fixed_in_build_field_id.nil?
141
+
142
+ headers = { "Authorization" => "Basic #{jira_info.auth_token}",
143
+ "Content-Type" => "application/json" }
144
+
145
+ issues.each do |issue_key|
146
+ #try to perform the transition
147
+ if jira_info.build_complete_transition_id.nil?
148
+ jira_info.update_build_complete_transition(issue_key)
149
+ end
150
+
151
+ #still nil? Can't perform this transition
152
+ if jira_info.build_complete_transition_id.nil?
153
+ puts "Could no update issue #{issue_key}: could not find transition"
154
+ next
155
+ end
156
+
157
+ params = {
158
+ transition: {
159
+ id: jira_info.build_complete_transition_id
160
+ },
161
+ fields: {
162
+ jira_info.fixed_in_build_field_id => build
163
+ }
164
+ }
165
+ transition_url = File.join(jira_url, issue_key, 'transitions')
166
+
167
+ puts "Updating issue #{issue_key}"
168
+ begin
169
+ issue_response = RestClient.post(transition_url, JSON.generate(params), headers=headers)
170
+ rescue RestClient::Exception => e
171
+ puts "Error updating issue #{issue_key}: Error code #{e.response.code}"
172
+ end
173
+ end
174
+ end
175
+
176
+ def self.pull_travis_options(options)
177
+ puts "Pulling parameters from Travis-CI environment variables where needed...."
178
+ options.commit_range = ENV["TRAVIS_COMMIT_RANGE"] if options.commit_range == nil
179
+ options.build = ENV["TRAVIS_BUILD_NUMBER"] if options.build == nil
180
+ end
181
+
182
+ def self.pull_team_city_options(options)
183
+ puts "Pulling parameters from TeamCity environment variables where needed...."
184
+ options.commit_range = ENV["TEAMCITY_COMMIT_RANGE"] if options.commit_range == nil
185
+ options.build = ENV["BUILD_NUMBER"] if options.build == nil
186
+ end
187
+
188
+ def self.pull_common_options(options)
189
+ options.site = ENV["JIRA_URL"] if options.site == nil
190
+ options.username = ENV["JIRA_USERNAME"] if options.username == nil
191
+ options.password = ENV["JIRA_PASSWORD"] if options.password == nil
192
+ end
193
+
194
+ def self.validate_options(options)
195
+ valid_options = true
196
+ if options.commit_range == nil
197
+ puts "Commit range is required. None specified."
198
+ puts "You can specify this in TeamCity by running 'teamcity_git_range_fetch.rb' before this step." if ENV["TEAMCITY_VERSION"]
199
+ valid_options = false
200
+ end
201
+ if options.site == nil
202
+ puts "Site parameter is required, or use JIRA_URL environment variable on build servers"
203
+ valid_options = false
204
+ end
205
+ if options.username == nil
206
+ puts "No username for JIRA provided. Use JIRA_USERNAME environment variable on build servers"
207
+ valid_options = false
208
+ end
209
+ if options.password == nil
210
+ puts "No password for JIRA provided. Use JIRA_PASSWORD environment variable on build servers"
211
+ valid_options = false
212
+ end
213
+
214
+ valid_options
215
+ end
216
+
217
+ def self.perform_jira_update(options = nil)
218
+ options = Options.new if options == nil
219
+ if ENV["TRAVIS"]
220
+ pull_travis_options(options)
221
+ # Detect running on TeamCity for common prarams
222
+ elsif ENV["TEAMCITY_VERSION"]
223
+ pull_team_city_options(options)
224
+ end
225
+ pull_common_options(options)
226
+
227
+ if validate_options(options)
228
+ logs = get_git_history(options.commit_range)
229
+ issue_set = find_jira_issues(logs)
230
+
231
+ jira_info = JiraInfo.new options.site, options.username, options.password
232
+ jira_update(jira_info, issue_set, options.build)
233
+ end
234
+ end
235
+ end
236
+ end
237
+
238
+ if __FILE__ == $0
239
+ options = WTBuildHelpers::Jira::Parser.parse(ARGV)
240
+ WTBuildHelpers::Jira.perform_jira_update(options)
241
+ end
@@ -0,0 +1,40 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'base64'
4
+ require 'json'
5
+ require 'rest_client'
6
+ require 'pp'
7
+
8
+ module WTBuildHelpers
9
+ module TeamCity
10
+ def self.fetch_commit_range(teamcity_url, build_type_id, username, password)
11
+
12
+ auth_token = Base64.encode64("#{username}:#{password}")
13
+ headers = { "Authorization" => "Basic #{auth_token}",
14
+ "Accept" => "application/json"
15
+ }
16
+
17
+ full_url = "#{teamcity_url}/app/rest/buildTypes/id:#{build_type_id}/builds/status:SUCCESS"
18
+
19
+ response = RestClient.get(full_url, headers=headers)
20
+ json_response = JSON.parse(response.body)
21
+
22
+ start_revision = ENV["BUILD_VCS_NUMBER"]
23
+ end_revision = json_response["revisions"]["revision"][0]["version"]
24
+
25
+ puts "##teamcity[setParameter name='env.TEAMCITY_COMMIT_RANGE' value='#{start_revision}..#{end_revision}']"
26
+ end
27
+ end
28
+ end
29
+
30
+ if __FILE__ == $0
31
+ if ARGV.length < 4
32
+ puts "Usage: teamcity_git_range_fetch.rb [TeamCity Url] [TeamCity Build Type Id] [TeamCity User Name] [TeamCity Password]"
33
+ puts "These parameters can be passed from TeamCity with the following line: "
34
+ puts " teamcity_git_range_fetch.rb \"%teamcity.serverUrl%\" \"%system.teamcity.buildType.id%\" \"%system.teamcity.auth.userId%\" \"%system.teamcity.auth.password%\""
35
+
36
+ exit
37
+ end
38
+
39
+ WTBuildHelpers::TeamCity.fetch_commit_range(ARGV[0], ARGV[1], ARGV[2], ARGV[3])
40
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: WTBuildHelpers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - WillowTreeApps
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-11-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: OptionParser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.8.0
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.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ description:
70
+ email:
71
+ - jeff.ward@willowtreeapps.com
72
+ executables:
73
+ - wtbuild_jira_update
74
+ - wtbuild_teamcity_fetch_git_range
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - WTBuildHelpers.gemspec
84
+ - bin/console
85
+ - bin/setup
86
+ - exe/wtbuild_jira_update
87
+ - exe/wtbuild_teamcity_fetch_git_range
88
+ - lib/WTBuildHelpers.rb
89
+ - lib/WTBuildHelpers/version.rb
90
+ - lib/jira_tasks.rb
91
+ - lib/teamcity_git_range_fetch.rb
92
+ homepage:
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.2.2
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Helpers for performing common WillowTree build tasks and integrations
116
+ test_files: []