flowdock-build-notifier 0.0.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: 60e8e5babf52a78ed4235f6e6aff3894d8dc9154
4
+ data.tar.gz: 8f7f948ed568fd9f40330bdaab01f9941dd862b6
5
+ SHA512:
6
+ metadata.gz: fb0c7dc0b8b2ee23a74a3a35903ad8586f52bcf05f84ad44e3a2c22cc446873467e0842d2f2920fdd7ec0a5f764bf308d25fd954e559284e1010478fac96e20a
7
+ data.tar.gz: 94de09af069a4b475e5bd018e81352f883682ef44eaa7943df7bf45c4a3e979420e9849e505d6ff7dfb3d9a9477ba5e83eac2867bb90c058a5e08d075cc78495
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .github_access_token
6
+ .pivotal_api_token
7
+ .ruby-gemset
8
+ .ruby-version
9
+ .yardoc
10
+ Gemfile.lock
11
+ InstalledFiles
12
+ _yardoc
13
+ coverage
14
+ doc/
15
+ lib/bundler/man
16
+ pkg
17
+ rdoc
18
+ spec/reports
19
+ test/tmp
20
+ test/version_tmp
21
+ tmp
@@ -0,0 +1 @@
1
+ flowdock_notify
@@ -0,0 +1 @@
1
+ ruby-2.1.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in flowdock-build-notifier.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Aaron Jensen
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,86 @@
1
+ # FlowdockNotify
2
+
3
+ This is used by the build agent to notify the person who (most likely)
4
+ started the build that their build is complete, whether or not it failed
5
+ or passed.
6
+
7
+ The teamcity api is used to fetch information about the build because we
8
+ cannot find it out in the environment.
9
+
10
+ ## Installation
11
+
12
+ 1. Add this gem to your Gemfile
13
+
14
+ 2. Set up a TeamCity account with access to all the projects being reported on
15
+ and a Flowdock account with access to your team's flow - it will be the
16
+ account sending messages to your team members. Put these bots'
17
+ credentials into the configuration below.
18
+
19
+ 2. Make a `.flowdock_build_notifier.yml` file in the root of your project. An
20
+ example is given below:
21
+
22
+ ```yaml
23
+ flowdock_user_token: SECRET_FLOWDOCK_USER_TOKEN
24
+ flow_name: FLOW_NAME
25
+
26
+ teamcity_url: https://teamcity.your_account.com
27
+ teamcity_user: SECRET_TEAMCITY_USER_NAME
28
+ teamcity_password: SECRET_TEAMCITY_USER_PASSWORD
29
+
30
+ email_map:
31
+ miranda@gmail.com: miranda@company.com
32
+ jj@gmail.com: jacobson@company.com
33
+ ```
34
+
35
+ For privacy, you should put this file in your .gitignore.
36
+ Alternatively, TeamCity login information and flowdock user token can be left
37
+ out of the yaml configuration file by assigning the following ENV variables
38
+ on TeamCity if you prefer.
39
+
40
+ ```
41
+ ENV['FLOWDOCK_USER_TOKEN']
42
+ ENV['FLOWDOCK_NOTIFIER_TEAMCITY_USER']
43
+ ENV['FLOWDOCK_NOTIFIER_TEAMCITY_PASSWORD']
44
+ ```
45
+
46
+ The email map is used to connect the author of the last commit to the
47
+ corresponding Flowdock account.
48
+
49
+ 3. Under project settings on TeamCity, upload the following xml document as a
50
+ meta-runner:
51
+
52
+ ```xml
53
+ <?xml version="1.0" encoding="UTF-8"?>
54
+ <meta-runner name="Flowdock Notify">
55
+ <description>Notify build status via flowdock</description>
56
+ <settings>
57
+ <parameters />
58
+ <build-runners>
59
+ <runner name="" type="simpleRunner">
60
+ <parameters>
61
+ <param name="command.executable" value="bundle exec flowdock_notify" />
62
+ <param name="command.parameters" value="%teamcity.build.id%" />
63
+ <param name="teamcity.step.mode" value="default" />
64
+ </parameters>
65
+ </runner>
66
+ </build-runners>
67
+ <requirements />
68
+ </settings>
69
+ </meta-runner>
70
+ ```
71
+
72
+ ![Meta-runner section](./readme_screenshots/meta_runners_section.png)
73
+
74
+
75
+ 4. Set up your build configuration steps to run `bundle install`
76
+ initially. Make a final step which executes the notifier meta-runner
77
+ regardless of previous failures.
78
+
79
+ ![Meta-runner configuration step](./readme_screenshots/set_meta_runner_step.png)
80
+
81
+ ---
82
+
83
+ ![Use meta-runner in all cases](./readme_screenshots/use_runner_even_if_previous_steps_fail.png)
84
+
85
+ 5. If you want a particular build to report failure in the main flow instead of
86
+ private messages, set `ENV['FLOWDOCK_NOTIFY_ALL_ON_FAILURE']` to true.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/flowdock_build_notifier'
3
+
4
+ begin
5
+ if ARGV.first == '--author_email'
6
+ puts FlowdockBuildNotifier::FlowdockNotification.new(nil).author_email
7
+ else
8
+ FlowdockBuildNotifier::FlowdockNotification.new(ARGV.first).notify
9
+ end
10
+ rescue => e
11
+ $stderr.puts e
12
+ $stderr.puts e.backtrace
13
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'flowdock_build_notifier/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "flowdock-build-notifier"
8
+ spec.version = FlowdockNotify::VERSION
9
+ spec.authors = ["Aaron Jensen", "Shaun Dern"]
10
+ spec.email = ["aaronjensen@gmail.com", "shaun@substantial.com"]
11
+ spec.summary = %q{Notifies Flowdock about builds.}
12
+ spec.description = %q{Notifies Flowdock about builds.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
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_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency "flowdock"
25
+ end
@@ -0,0 +1,50 @@
1
+ require 'flowdock'
2
+
3
+ require_relative 'flowdock_build_notifier/configuration'
4
+ require_relative 'flowdock_build_notifier/notification_message'
5
+ require_relative 'flowdock_build_notifier/flowdock_message_sender'
6
+ require_relative 'flowdock_build_notifier/build_metadata'
7
+ require_relative 'flowdock_build_notifier/flowdock_message_sender_factory'
8
+
9
+ module FlowdockBuildNotifier
10
+ class FlowdockNotification
11
+ attr_reader :build_id, :config
12
+
13
+ def initialize(build_id)
14
+ @build_id = build_id
15
+ @config = Configuration.load
16
+ end
17
+
18
+ def notify
19
+ sender = FlowdockMessageSenderFactory
20
+ .new(config: config)
21
+ .create_sender(notify_email)
22
+
23
+ sender.send_message(message)
24
+ notify_all if ENV['FLOWDOCK_NOTIFY_ALL_ON_FAILURE'] && build.status == "FAILURE"
25
+ end
26
+
27
+ def notify_all
28
+ TeamRoomSender
29
+ .new(config: config)
30
+ .send_message("#{message} @all")
31
+ end
32
+
33
+ def message
34
+ NotificationMessage.new(build)
35
+ end
36
+
37
+ def build
38
+ @build ||= BuildMetadata.new(config: config).tap { |metadata| metadata.fetch(build_id) }
39
+ end
40
+
41
+ def author_email
42
+ `git show --format=format:%ae`.split("\n").first
43
+ end
44
+
45
+ def notify_email
46
+ return File.read('.flowdock_notify_email').strip if File.exists? '.flowdock_notify_email'
47
+ author_email
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,43 @@
1
+ require 'rexml/document'
2
+ require 'net/https'
3
+
4
+ require_relative 'configuration'
5
+
6
+ module FlowdockBuildNotifier
7
+ class BuildMetadata
8
+ attr_reader :metadata, :config
9
+
10
+ def initialize(config: Configuration.load)
11
+ @config = config
12
+ end
13
+
14
+ def fetch(build_id)
15
+ build_uri = URI("#{config.teamcity_url}/httpAuth/app/rest/builds/#{build_id}")
16
+
17
+ Net::HTTP.start(build_uri.host, build_uri.port, use_ssl: true) do |http|
18
+ request = Net::HTTP::Get.new(build_uri)
19
+ request.basic_auth config.teamcity_user, config.teamcity_password
20
+ @result = http.request(request).body
21
+ end
22
+ @metadata = REXML::Document.new(@result)
23
+ end
24
+
25
+ def status
26
+ metadata.root.attributes['status']
27
+ end
28
+
29
+ def url
30
+ metadata.root.attributes['webUrl']
31
+ end
32
+
33
+ def branch
34
+ metadata.root.attributes['branchName']
35
+ end
36
+
37
+ def name
38
+ project_name = metadata.root.elements['buildType'].attributes['projectName']
39
+ name = metadata.root.elements['buildType'].attributes['name']
40
+ [project_name, name].compact.join(" :: ")
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,27 @@
1
+ require 'yaml'
2
+
3
+ module FlowdockBuildNotifier
4
+ class Configuration
5
+ FLOWDOCK_CONFIG = '.flowdock_build_notifier.yml'
6
+
7
+ def self.load
8
+ new(YAML.load_file(FLOWDOCK_CONFIG))
9
+ rescue Errno::ENOENT
10
+ raise "#{FLOWDOCK_CONFIG} configuration not found"
11
+ end
12
+
13
+ attr_reader :flow_name, :flowdock_user_token, :teamcity_user,
14
+ :teamcity_password, :teamcity_url, :email_map
15
+
16
+ def initialize(config)
17
+ @flowdock_user_token = ENV['FLOWDOCK_USER_TOKEN'] || config.fetch('flowdock_user_token')
18
+ @flow_name= config.fetch('flow_name')
19
+
20
+ @email_map = config.fetch('email_map') { {} }
21
+
22
+ @teamcity_url = config.fetch('teamcity_url')
23
+ @teamcity_user = ENV['FLOWDOCK_NOTIFIER_TEAMCITY_USER'] || config.fetch('teamcity_user')
24
+ @teamcity_password = ENV['FLOWDOCK_NOTIFIER_TEAMCITY_PASSWORD'] || config.fetch('teamcity_password')
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,56 @@
1
+ require_relative 'configuration'
2
+
3
+ require 'flowdock'
4
+
5
+ module FlowdockBuildNotifier
6
+ class FlowdockMessageSender
7
+ attr_reader :config, :client
8
+
9
+ def initialize(options = {})
10
+ @options = options
11
+ @config = @options.fetch(:config) { Configuration.load }
12
+ @client = @options.fetch(:client) { Flowdock::Client.new(api_token: config.flowdock_user_token) }
13
+ end
14
+
15
+ def send_message(message)
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def messages_path
20
+ raise NotImplementedError
21
+ end
22
+ end
23
+
24
+ class PrivateMessageSender < FlowdockMessageSender
25
+ def user_id
26
+ @options.fetch :user_id
27
+ end
28
+
29
+ def send_message(message)
30
+ client.post("/private/#{user_id}/messages", event: 'message', content: message.to_s)
31
+ end
32
+ end
33
+
34
+ class TeamRoomSender < FlowdockMessageSender
35
+ def flow
36
+ @flow_id ||= client.get('/flows').detect do |flow|
37
+ flow['name'] == config.flow_name
38
+ end
39
+ end
40
+
41
+ def send_message(message)
42
+ client.chat_message(flow: flow['id'], content: message.to_s)
43
+ end
44
+ end
45
+
46
+ class UnknownUserSender < TeamRoomSender
47
+ def email
48
+ @options.fetch :email
49
+ end
50
+
51
+ def send_message(message)
52
+ super
53
+ super "Please add #{email} to .flowdock_build_notifier.yml"
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,31 @@
1
+ require_relative 'flowdock_message_sender'
2
+ require_relative 'configuration'
3
+
4
+ require 'flowdock'
5
+
6
+ module FlowdockBuildNotifier
7
+ class FlowdockMessageSenderFactory
8
+ attr_reader :config, :client
9
+
10
+ def initialize(config: Configuration.load, client: Flowdock::Client.new(api_token: config.flowdock_user_token))
11
+ @config = config
12
+ @client = client
13
+ end
14
+
15
+ def create_sender(email)
16
+ user = user_by_email(email)
17
+ return UnknownUserSender.new(email: email, config: config) unless user
18
+ PrivateMessageSender.new(user_id: user['id'], client: client)
19
+ end
20
+
21
+ def users
22
+ @users ||= client.get('/users')
23
+ end
24
+
25
+ def user_by_email(email)
26
+ @user ||= users.detect do |user|
27
+ user['email'] == config.email_map[email] || user['email'] == email
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ module FlowdockBuildNotifier
2
+ class NotificationMessage
3
+ attr_reader :build
4
+ def initialize(build)
5
+ @build = build
6
+ end
7
+
8
+ def to_s
9
+ "#{status}: \"#{build.name}\" build#{branch} - #{build.url}"
10
+ end
11
+
12
+ def branch
13
+ " for branch #{build.branch}" if build.branch
14
+ end
15
+
16
+ def status
17
+ {
18
+ "SUCCESS" => "#{pass_status}",
19
+ "FAILURE" => "❌ FAILED",
20
+ "UNKNOWN" => "🚧 CANCELED",
21
+ }[build.status]
22
+ end
23
+
24
+ def pass_status
25
+ case build.name
26
+ when /deploy/i
27
+ "🚀 DEPLOYED"
28
+ when /smoke/i
29
+ "🚬 SMOKED"
30
+ else
31
+ "✅ PASSED"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module FlowdockNotify
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flowdock-build-notifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Jensen
8
+ - Shaun Dern
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-09-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.5'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.5'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: flowdock
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: Notifies Flowdock about builds.
57
+ email:
58
+ - aaronjensen@gmail.com
59
+ - shaun@substantial.com
60
+ executables:
61
+ - flowdock_notify
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - ".gitignore"
66
+ - ".ruby-gemset.template"
67
+ - ".ruby-version.template"
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - bin/flowdock_notify
73
+ - flowdock-build-notifier.gemspec
74
+ - lib/flowdock_build_notifier.rb
75
+ - lib/flowdock_build_notifier/build_metadata.rb
76
+ - lib/flowdock_build_notifier/configuration.rb
77
+ - lib/flowdock_build_notifier/flowdock_message_sender.rb
78
+ - lib/flowdock_build_notifier/flowdock_message_sender_factory.rb
79
+ - lib/flowdock_build_notifier/notification_message.rb
80
+ - lib/flowdock_build_notifier/version.rb
81
+ - readme_screenshots/meta_runners_section.png
82
+ - readme_screenshots/set_meta_runner_step.png
83
+ - readme_screenshots/use_runner_even_if_previous_steps_fail.png
84
+ homepage: ''
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.4.5
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Notifies Flowdock about builds.
108
+ test_files: []