deploy-info 0.1.0

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: e359963ce3d6e67dc704ad1b479e3de0efe05d36
4
+ data.tar.gz: ac403a7fea14a45888baf6e0eed78a67c57effd6
5
+ SHA512:
6
+ metadata.gz: 967779ad952e52d021a93cb31859601d48bcaa698d89a2d0886f9106deabece9db9c4f263561636afa1c93774407c9c9aadde0aa2e6dfa56c84b167463a33e93
7
+ data.tar.gz: df1f64fc711c60461705d092276b51fd86cbbef802691228d96bb0e3cc3e98b28ddd8e28b58c58c1142a982f2e77ce960abea713555f6636eed67ed4f8b2eadc
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *~
2
+ *#
3
+ .#*
4
+ \#*#
5
+ .*.sw[a-z]
6
+ *.un~
7
+ pkg/
8
+ vendor/
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,36 @@
1
+ before_script:
2
+ - ruby -v
3
+ - which ruby
4
+ - gem install bundler --no-ri --no-rdoc
5
+ - bundle install --jobs $(nproc) --path vendor/bundle
6
+
7
+ test:Ruby 2.2:
8
+ image: ruby:2.2
9
+ cache:
10
+ paths:
11
+ - .bundle
12
+ - vendor/bundle
13
+ script:
14
+ - bundle exec rubocop
15
+ tags:
16
+ - ruby
17
+ except:
18
+ - tags
19
+
20
+ release:Ruby 2.2:
21
+ image: ruby:2.2
22
+ cache:
23
+ paths:
24
+ - .bundle
25
+ - vendor/bundle
26
+ script:
27
+ - bundle exec rubocop
28
+ - bundle exec rake build
29
+ artifacts:
30
+ name: "deploy-info-$CI_BUILD_REF_NAME"
31
+ paths:
32
+ - pkg/*.gem
33
+ tags:
34
+ - ruby
35
+ only:
36
+ - tags
data/.rubocop.yml ADDED
@@ -0,0 +1,12 @@
1
+ Style/ModuleFunction:
2
+ Enabled: false
3
+
4
+ Style/WordArray:
5
+ Enabled: false
6
+
7
+ Style/FileName:
8
+ Enabled: false
9
+
10
+ AllCops:
11
+ Include:
12
+ - lib/
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'github_api' # => Github API Interaction
4
+ # => gem 'hashie' # => Data Structure
5
+ # => gem 'logify' # => Logging
6
+ gem 'mixlib-cli' # => Option Parsing
7
+ gem 'rack-cache' # => Cache Responses
8
+ gem 'sinatra' # => Web Server
9
+ gem 'sinatra-contrib' # => For namespaces
10
+
11
+ group :development do
12
+ gem 'rake'
13
+ gem 'rspec'
14
+ gem 'rubocop'
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,91 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.4.0)
5
+ ast (2.3.0)
6
+ backports (3.6.8)
7
+ descendants_tracker (0.0.4)
8
+ thread_safe (~> 0.3, >= 0.3.1)
9
+ diff-lcs (1.2.5)
10
+ faraday (0.9.2)
11
+ multipart-post (>= 1.2, < 3)
12
+ github_api (0.14.5)
13
+ addressable (~> 2.4.0)
14
+ descendants_tracker (~> 0.0.4)
15
+ faraday (~> 0.8, < 0.10)
16
+ hashie (>= 3.4)
17
+ oauth2 (~> 1.0)
18
+ hashie (3.4.4)
19
+ jwt (1.5.4)
20
+ mixlib-cli (1.7.0)
21
+ multi_json (1.12.1)
22
+ multi_xml (0.5.5)
23
+ multipart-post (2.0.0)
24
+ oauth2 (1.2.0)
25
+ faraday (>= 0.8, < 0.10)
26
+ jwt (~> 1.0)
27
+ multi_json (~> 1.3)
28
+ multi_xml (~> 0.5)
29
+ rack (>= 1.2, < 3)
30
+ parser (2.3.1.2)
31
+ ast (~> 2.2)
32
+ powerpack (0.1.1)
33
+ rack (1.6.4)
34
+ rack-cache (1.6.1)
35
+ rack (>= 0.4)
36
+ rack-protection (1.5.3)
37
+ rack
38
+ rack-test (0.6.3)
39
+ rack (>= 1.0)
40
+ rainbow (2.1.0)
41
+ rake (11.2.2)
42
+ rspec (3.5.0)
43
+ rspec-core (~> 3.5.0)
44
+ rspec-expectations (~> 3.5.0)
45
+ rspec-mocks (~> 3.5.0)
46
+ rspec-core (3.5.2)
47
+ rspec-support (~> 3.5.0)
48
+ rspec-expectations (3.5.0)
49
+ diff-lcs (>= 1.2.0, < 2.0)
50
+ rspec-support (~> 3.5.0)
51
+ rspec-mocks (3.5.0)
52
+ diff-lcs (>= 1.2.0, < 2.0)
53
+ rspec-support (~> 3.5.0)
54
+ rspec-support (3.5.0)
55
+ rubocop (0.42.0)
56
+ parser (>= 2.3.1.1, < 3.0)
57
+ powerpack (~> 0.1)
58
+ rainbow (>= 1.99.1, < 3.0)
59
+ ruby-progressbar (~> 1.7)
60
+ unicode-display_width (~> 1.0, >= 1.0.1)
61
+ ruby-progressbar (1.8.1)
62
+ sinatra (1.4.7)
63
+ rack (~> 1.5)
64
+ rack-protection (~> 1.4)
65
+ tilt (>= 1.3, < 3)
66
+ sinatra-contrib (1.4.7)
67
+ backports (>= 2.0)
68
+ multi_json
69
+ rack-protection
70
+ rack-test
71
+ sinatra (~> 1.4.0)
72
+ tilt (>= 1.3, < 3)
73
+ thread_safe (0.3.5)
74
+ tilt (2.0.5)
75
+ unicode-display_width (1.1.0)
76
+
77
+ PLATFORMS
78
+ ruby
79
+
80
+ DEPENDENCIES
81
+ github_api
82
+ mixlib-cli
83
+ rack-cache
84
+ rake
85
+ rspec
86
+ rubocop
87
+ sinatra
88
+ sinatra-contrib
89
+
90
+ BUNDLED WITH
91
+ 1.12.5
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Brian Dwyer - Intelligent Digital Services
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,58 @@
1
+ # Deploy-Info
2
+ * Deployment Notification Provider for RunDeck
3
+ * Pulls information potentially not readily available to RunDeck
4
+ * One simple POST from RunDeck instead of a script (NewRelic Deploys require a JSON POST)
5
+ * Maybe Eventually: Record last deployed revision locally and feed it back for consumption/display inside RunDeck
6
+
7
+ ## Background
8
+ This project's initial purpose is/was to fire off NewRelic & Rollbar deployment notifications from RunDeck. It can be difficult to grab information such as a commit SHA when you may just be deploying a branch from RunDeck. This serves to fill that gap and ensure the revision field is populated appropriately, and it can also be utilized to keep your NewRelic API key out of visibility in the RunDeck console.
9
+
10
+ **NOTE:** This API should **NOT** be exposed to the world unless you plan to secure it with a reverse-proxy or something. It is intended to only be bound to `localhost` on the same server as RunDeck.
11
+
12
+ ## Running as a Service
13
+ You'll likely want to run this as a service, `SystemD` or `Upstart` will likely be your friend in this regard.
14
+
15
+ ## Security
16
+ You should lock down permissions on all configuration files in this project to only the user which this runs as...
17
+
18
+ To run this project securely, **DON'T** run it as the RunDeck user.
19
+
20
+ ## Caching
21
+ This leans on `rack-cache` to serve as a caching mechanism. The objective here was to make sure we don't pummel the Chef API with redundant queries.
22
+ * Timeout can be configured via the `cache_timeout` setting. **Default:** *30 seconds*
23
+
24
+
25
+ ## Installation
26
+
27
+ Add this line to your application's Gemfile:
28
+
29
+ ```ruby
30
+ gem 'deploy-info'
31
+ ```
32
+
33
+ And then execute:
34
+
35
+ $ bundle
36
+
37
+ Or install it yourself as:
38
+
39
+ $ gem install deploy-info
40
+
41
+ ## Usage
42
+
43
+ TODO: Write usage instructions here
44
+
45
+ ## Development
46
+
47
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
48
+
49
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
50
+
51
+ ## Contributing
52
+
53
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bdwyertech/deploy-info. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
54
+
55
+
56
+ ## License
57
+
58
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'bundler/setup'
7
+ require 'chef-rundeck'
8
+
9
+ # You can add fixtures and/or initialization code here to make experimenting
10
+ # with your gem easier. You can also use a different console, if you like.
11
+
12
+ # (If you use this, don't forget to add pry to your Gemfile!)
13
+ # require "pry"
14
+ # Pry.start
15
+
16
+ require 'irb'
17
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+ # rubocop: disable LineLength
3
+
4
+ lib = File.expand_path('../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require 'deploy-info/version'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = 'deploy-info'
10
+ spec.version = DeployInfo::VERSION
11
+ spec.authors = ['Brian Dwyer']
12
+ spec.email = ['bdwyer@IEEE.org']
13
+
14
+ spec.summary = %(Deployment Notification and State Provider)
15
+ # => spec.description = %q(TODO: Write a longer description or delete this line.)
16
+ spec.homepage = 'https://github.com/bdwyertech/deploy-info'
17
+ spec.license = 'MIT'
18
+
19
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
20
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
21
+ if spec.respond_to?(:metadata)
22
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
23
+ else
24
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
25
+ end
26
+
27
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
+ spec.bindir = 'exe'
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ['lib']
31
+
32
+ # => Dependencies
33
+ spec.add_runtime_dependency 'github_api', '~> 0.14'
34
+ spec.add_runtime_dependency 'mixlib-cli', '~> 1.6'
35
+ spec.add_runtime_dependency 'rack-cache', '~> 1.6'
36
+ spec.add_runtime_dependency 'sinatra', '~> 1.4'
37
+ spec.add_runtime_dependency 'sinatra-contrib', '~> 1.4'
38
+
39
+ # => Development Dependencies
40
+ spec.add_development_dependency 'bundler', '~> 1.12'
41
+ spec.add_development_dependency 'rake', '~> 10.0'
42
+ spec.add_development_dependency 'rspec', '~> 3.0'
43
+ spec.add_development_dependency 'rubocop'
44
+ end
data/exe/deploy-info ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # Deployment Information Provider for RunDeck
4
+ # Brian Dwyer - Intelligent Digital Services - 9/1/16
5
+
6
+ lib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
8
+
9
+ # => Catch Ctrl+C's to avoid stack traces
10
+ Signal.trap('INT') { abort }
11
+
12
+ require 'deploy-info'
13
+
14
+ DeployInfo::CLI.run(ARGV)
@@ -0,0 +1,16 @@
1
+ # encoding: UTF-8
2
+ # rubocop: disable LineLength
3
+ # Deployment Information Provider for RunDeck
4
+ # Brian Dwyer - Intelligent Digital Services - 9/1/16
5
+
6
+ require 'deploy-info/cli'
7
+ require 'deploy-info/config'
8
+ require 'deploy-info/state'
9
+ require 'deploy-info/util'
10
+ require 'deploy-info/version'
11
+
12
+ # => Deployment Information API
13
+ module DeployInfo
14
+ # => The Sinatra API should be Lazily-Loaded, such that the CLI arguments and/or configuration files are respected
15
+ autoload :API, 'deploy-info/api'
16
+ end
@@ -0,0 +1,124 @@
1
+ # Encoding: UTF-8
2
+ # rubocop: disable LineLength
3
+ #
4
+ # Gem Name:: deploy-info
5
+ # DeployInfo:: API
6
+ #
7
+ # Copyright (C) 2016 Brian Dwyer - Intelligent Digital Services
8
+ #
9
+ # All rights reserved - Do Not Redistribute
10
+ #
11
+
12
+ # => NOTE: Anything other than a STATUS 200 will trigger an error in the RunDeck plugin due to a hardcode in org.boon.HTTP
13
+
14
+ require 'sinatra/base'
15
+ require 'sinatra/namespace'
16
+ require 'json'
17
+ require 'rack/cache'
18
+ require 'deploy-info/notifier'
19
+ require 'deploy-info/config'
20
+ require 'deploy-info/state'
21
+
22
+ # => Deployment Information Provider for RunDeck
23
+ module DeployInfo
24
+ # => HTTP API
25
+ class API < Sinatra::Base
26
+ #######################
27
+ # => Sinatra <= #
28
+ #######################
29
+
30
+ # => Configure Sinatra
31
+ enable :logging, :static, :raise_errors # => disable :dump_errors, :show_exceptions
32
+ set :port, Config.port || 8080
33
+ set :bind, Config.bind || 'localhost'
34
+ set :environment, Config.environment || :production
35
+
36
+ # => Enable NameSpace Support
37
+ register Sinatra::Namespace
38
+
39
+ if development?
40
+ require 'sinatra/reloader'
41
+ register Sinatra::Reloader
42
+ end
43
+
44
+ use Rack::Cache do
45
+ set :verbose, true
46
+ set :metastore, 'file:' + File.join(Dir.tmpdir, 'rack', 'meta')
47
+ set :entitystore, 'file:' + File.join(Dir.tmpdir, 'rack', 'body')
48
+ end
49
+
50
+ ########################
51
+ # => JSON API <= #
52
+ ########################
53
+
54
+ # => Current Configuration & Healthcheck Endpoint
55
+ get '/config' do
56
+ content_type 'application/json'
57
+ JSON.pretty_generate(
58
+ [
59
+ DeployInfo.inspect + ' is up and running!',
60
+ 'Author: ' + Config.author,
61
+ 'Environment: ' + Config.environment.to_s,
62
+ 'Root: ' + Config.root.to_s,
63
+ 'Config File: ' + (Config.config_file if File.exist?(Config.config_file)).to_s,
64
+ 'State File: ' + (Config.state_file if File.exist?(Config.state_file)).to_s,
65
+ { State: State.state.map { |n| n[:name] } },
66
+ 'Params: ' + params.inspect,
67
+ 'Cache Timeout: ' + Config.cache_timeout.to_s,
68
+ 'BRIAN IS COOooooooL',
69
+ { AppConfig: Config.options },
70
+ { 'Sinatra Info' => env }
71
+ ].compact
72
+ )
73
+ end
74
+
75
+ get '/state' do
76
+ content_type 'application/json'
77
+ State.state.to_json
78
+ end
79
+
80
+ ########################
81
+ # => JSON API <= #
82
+ ########################
83
+
84
+ namespace '/deploy/v1' do
85
+ # => Define our common namespace parameters
86
+ before do
87
+ # => This is a JSON API
88
+ content_type 'application/json'
89
+
90
+ # => Make the Params Globally Accessible
91
+ Config.define_setting :query_params, params
92
+
93
+ # => Parameter Overrides
94
+ Github.configure do |cfg|
95
+ cfg.oauth_token = params['gh_oauth_token'] || Config.github_oauth_token
96
+ end
97
+ end
98
+
99
+ # => Clean Up
100
+ after do
101
+ # => Reset the API Client to Default Values
102
+ # => Notifier.reset!
103
+ end
104
+
105
+ # => Notify Deploys
106
+ post '/notify' do
107
+ resp = {}
108
+ resp['NewRelic'] = JSON.parse(Notifier.newrelic.body) if params['nr_app_id']
109
+ resp['Rollbar'] = JSON.parse(Notifier.rollbar.body) if params['rb_token']
110
+ resp.to_json
111
+ end
112
+
113
+ # => Retrieve Currently Deployed Revision
114
+ get '/revision' do
115
+ # => PLACEHOLDER
116
+ end
117
+
118
+ # => Parse Revision
119
+ post '/revision' do
120
+ Notifier.revision
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,102 @@
1
+ # Encoding: UTF-8
2
+ # rubocop: disable LineLength, MethodLength, AbcSize
3
+ #
4
+ # Gem Name:: deploy-info
5
+ # DeployInfo:: CLI
6
+ #
7
+ # Copyright (C) 2016 Brian Dwyer - Intelligent Digital Services
8
+ #
9
+ # All rights reserved - Do Not Redistribute
10
+ #
11
+
12
+ require 'mixlib/cli'
13
+ require 'deploy-info/config'
14
+ require 'deploy-info/util'
15
+
16
+ module DeployInfo
17
+ #
18
+ # => Deploy-Info Launcher
19
+ #
20
+ module CLI
21
+ extend self
22
+ #
23
+ # => Options Parser
24
+ #
25
+ class Options
26
+ # => Mix-In the CLI Option Parser
27
+ include Mixlib::CLI
28
+
29
+ option :github_oauth_token,
30
+ short: '-g TOKEN',
31
+ long: '--github-oauth-token TOKEN',
32
+ description: 'OAuth Token to use for querying GitHub'
33
+
34
+ option :nr_api_key,
35
+ short: '-n KEY',
36
+ long: '--nr-api-key KEY',
37
+ description: 'NewRelic API Key for deploy notifications to NewRelic'
38
+
39
+ option :cache_timeout,
40
+ short: '-t CACHE_TIMEOUT',
41
+ long: '--timeout CACHE_TIMEOUT',
42
+ description: 'Sets the cache timeout in seconds for API query response data.'
43
+
44
+ option :config_file,
45
+ short: '-c CONFIG',
46
+ long: '--config CONFIG',
47
+ description: 'The configuration file to use, as opposed to command-line parameters (optional)'
48
+
49
+ option :state_file,
50
+ short: '-s STATE',
51
+ long: '--state-json STATE',
52
+ description: "The JSON file containing node state & auditing information (Default: #{Config.state_file})"
53
+
54
+ option :bind,
55
+ short: '-b HOST',
56
+ long: '--bind HOST',
57
+ description: "Listen on Interface or IP (Default: #{Config.bind})"
58
+
59
+ option :port,
60
+ short: '-p PORT',
61
+ long: '--port PORT',
62
+ description: "The port to run on. (Default: #{Config.port})"
63
+
64
+ option :environment,
65
+ short: '-e ENV',
66
+ long: '--env ENV',
67
+ description: 'Sets the environment for deploy-info to execute under. Use "development" for more logging.',
68
+ default: 'production'
69
+ end
70
+
71
+ # => Launch the Application
72
+ def run(argv = ARGV)
73
+ # => Parse CLI Configuration
74
+ cli = Options.new
75
+ cli.parse_options(argv)
76
+
77
+ # => Parse JSON Config File (If Specified & Exists)
78
+ json_config = Util.parse_json_config(cli.config[:config_file])
79
+
80
+ # => Grab the Default Values
81
+ default = DeployInfo::Config.options
82
+
83
+ # => Merge Configuration (JSON File Wins)
84
+ config = [default, json_config, cli.config].compact.reduce(:merge)
85
+
86
+ # => Apply Configuration
87
+ DeployInfo::Config.setup do |cfg|
88
+ cfg.config_file = config[:config_file]
89
+ cfg.cache_timeout = config[:cache_timeout].to_i
90
+ cfg.bind = config[:bind]
91
+ cfg.port = config[:port]
92
+ cfg.state_file = config[:state_file]
93
+ cfg.environment = config[:environment].to_sym
94
+ cfg.github_oauth_token = config[:github_oauth_token]
95
+ cfg.nr_api_key = config[:nr_api_key]
96
+ end
97
+
98
+ # => Launch the API
99
+ DeployInfo::API.run!
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,83 @@
1
+ # Encoding: UTF-8
2
+ #
3
+ # Gem Name:: deploy-info
4
+ # DeployInfo:: Config
5
+ #
6
+ # Copyright (C) 2016 Brian Dwyer - Intelligent Digital Services
7
+ #
8
+ # All rights reserved - Do Not Redistribute
9
+ #
10
+
11
+ require 'deploy-info/helpers/configuration'
12
+ require 'pathname'
13
+
14
+ module DeployInfo
15
+ # => This is the Configuration module.
16
+ module Config
17
+ extend self
18
+ extend Configuration
19
+
20
+ # => Gem Root Directory
21
+ define_setting :root, Pathname.new(File.expand_path('../../../', __FILE__))
22
+
23
+ # => My Name
24
+ define_setting :author, 'Brian Dwyer - Intelligent Digital Services'
25
+
26
+ # => Application Environment
27
+ define_setting :environment, :production
28
+
29
+ # => Sinatra Configuration
30
+ define_setting :port, '9128'
31
+ define_setting :bind, 'localhost'
32
+ define_setting :cache_timeout, 30
33
+
34
+ # => Config File
35
+ define_setting :config_file, File.join(root, 'config', 'config.json')
36
+
37
+ # => State File
38
+ define_setting :state_file, File.join(root, 'config', 'state.json')
39
+
40
+ #
41
+ # => API Configuration
42
+ #
43
+ # => Github OAuth Token
44
+ define_setting :github_oauth_token
45
+
46
+ # => NewRelic API Key
47
+ define_setting :nr_api_key
48
+
49
+ #
50
+ # => Facilitate Dynamic Addition of Configuration Values
51
+ #
52
+ # => @return [class_variable]
53
+ #
54
+ def add(config = {})
55
+ config.each do |key, value|
56
+ define_setting key.to_sym, value
57
+ end
58
+ end
59
+
60
+ #
61
+ # => Facilitate Dynamic Removal of Configuration Values
62
+ #
63
+ # => @return nil
64
+ #
65
+ def clear(config)
66
+ Array(config).each do |setting|
67
+ delete_setting setting
68
+ end
69
+ end
70
+
71
+ #
72
+ # => List the Configurable Keys as a Hash
73
+ #
74
+ # @return [Hash]
75
+ #
76
+ def options
77
+ map = DeployInfo::Config.class_variables.map do |key|
78
+ [key.to_s.tr('@', '').to_sym, class_variable_get(:"#{key}")]
79
+ end
80
+ Hash[map]
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,43 @@
1
+ # Encoding: UTF-8
2
+ # rubocop: disable LineLength
3
+ #
4
+ # Gem Name:: deploy-info
5
+ # DeployInfo:: Git
6
+ #
7
+ # Copyright (C) 2016 Brian Dwyer - Intelligent Digital Services
8
+ #
9
+ # All rights reserved - Do Not Redistribute
10
+ #
11
+
12
+ require 'deploy-info/config'
13
+ require 'github_api'
14
+
15
+ module DeployInfo
16
+ # => This is the Git Module. It interacts with Git resources.
17
+ module Git
18
+ extend self
19
+
20
+ def ghclient
21
+ # => Instantiate a new GitHub Client
22
+ Github::Client.new
23
+ end
24
+
25
+ def revision # rubocop: disable AbcSize
26
+ # => Grab the Supplied Revision
27
+ rev = Config.query_params['revision'] || return
28
+ return rev unless Config.query_params['gh_repo']
29
+
30
+ # => Break down the Params
31
+ org, repo = Config.query_params['gh_repo'].split('/').map { |r| String(r) }
32
+ return rev unless org && repo
33
+
34
+ begin
35
+ # => Pull the Shorthand SHA
36
+ ghclient.git_data.trees.get(org, repo, rev).first[1][0, 7]
37
+ rescue Github::Error::NotFound
38
+ # => Return the Supplied Revision if Github Borks
39
+ rev
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,57 @@
1
+ # Encoding: UTF-8
2
+ #
3
+ # Gem Name:: deploy-info
4
+ # Helper:: Configuration
5
+ #
6
+ # Author: Eli Fatsi - https://www.viget.com/articles/easy-gem-configuration-variables-with-defaults
7
+ # Contributor: Brian Dwyer - Intelligent Digital Services
8
+ #
9
+
10
+ # => Configuration Helper Module
11
+ module Configuration
12
+ #
13
+ # => Provides a method to configure an Application
14
+ # => Example:
15
+ # DeployInfo::Config.setup do |cfg|
16
+ # cfg.config_file = 'abc.json'
17
+ # cfg.app_name = 'GemBase'
18
+ # end
19
+ #
20
+ def setup
21
+ yield self
22
+ end
23
+
24
+ def define_setting(name, default = nil)
25
+ class_variable_set("@@#{name}", default)
26
+
27
+ define_class_method "#{name}=" do |value|
28
+ class_variable_set("@@#{name}", value)
29
+ end
30
+
31
+ define_class_method name do
32
+ class_variable_get("@@#{name}")
33
+ end
34
+ end
35
+
36
+ def delete_setting(name)
37
+ remove_class_variable("@@#{name}")
38
+
39
+ delete_class_method(name)
40
+ rescue NameError # => Handle Non-Existent Settings
41
+ return
42
+ end
43
+
44
+ private
45
+
46
+ def define_class_method(name, &block)
47
+ (class << self; self; end).instance_eval do
48
+ define_method name, &block
49
+ end
50
+ end
51
+
52
+ def delete_class_method(name)
53
+ (class << self; self; end).instance_eval do
54
+ undef_method name
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,82 @@
1
+ # Encoding: UTF-8
2
+ # rubocop: disable LineLength, AbcSize, MethodLength
3
+ #
4
+ # Gem Name:: deploy-info
5
+ # DeployInfo:: Notifier
6
+ #
7
+ # Copyright (C) 2016 Brian Dwyer - Intelligent Digital Services
8
+ #
9
+ # All rights reserved - Do Not Redistribute
10
+ #
11
+
12
+ require 'deploy-info/git'
13
+ require 'json'
14
+ require 'net/http'
15
+ require 'uri'
16
+
17
+ module DeployInfo
18
+ # => Deploy Notification Methods
19
+ module Notifier
20
+ extend self
21
+
22
+ ########################
23
+ # => NewRelic <= #
24
+ ########################
25
+
26
+ def newrelic
27
+ return unless Config.query_params['nr_app_id']
28
+
29
+ # => Grab the NewRelic Application ID
30
+ nr_app_id = Config.query_params['nr_app_id']
31
+
32
+ # => Build the URI & POST Request
33
+ uri = URI.parse("https://api.newrelic.com/v2/applications/#{nr_app_id}/deployments.json")
34
+ request = Net::HTTP::Post.new(uri)
35
+
36
+ # => Set Headers
37
+ request.content_type = 'application/json'
38
+ request['X-Api-Key'] = Config.query_params['nr_api_key'] || Config.nr_api_key
39
+ puts Config.nr_api_key
40
+
41
+ # => Build the JSON Payload
42
+ request.body = {
43
+ deployment: {
44
+ revision: Git.revision,
45
+ user: Config.query_params['user'],
46
+ description: Config.query_params['comment']
47
+ }
48
+ }.to_json
49
+
50
+ # => Send the Deployment Notification
51
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
52
+ http.request(request)
53
+ end
54
+ end
55
+
56
+ #######################
57
+ # => Rollbar <= #
58
+ #######################
59
+
60
+ def rollbar
61
+ # => Build the Data Structure
62
+ data = {}
63
+ data[:access_token] = Config.query_params['rb_token']
64
+ data[:environment] = Config.query_params['environment']
65
+ data[:revision] = Git.revision
66
+ data[:local_username] = Config.query_params['user']
67
+ data[:comment] = Config.query_params['comment']
68
+
69
+ # => Parse the Destination API URI
70
+ uri = URI.parse('https://api.rollbar.com/api/1/deploy/')
71
+
72
+ # => Construct the POST Request
73
+ request = Net::HTTP::Post.new(uri)
74
+ request.set_form_data(data)
75
+
76
+ # => Send the Deployment Notification
77
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
78
+ http.request(request)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,92 @@
1
+ # Encoding: UTF-8
2
+ # rubocop: disable LineLength
3
+ #
4
+ # Gem Name:: deploy-info
5
+ # DeployInfo:: State
6
+ #
7
+ # Copyright (C) 2016 Brian Dwyer - Intelligent Digital Services
8
+ #
9
+ # All rights reserved - Do Not Redistribute
10
+ #
11
+
12
+ require 'deploy-info/config'
13
+ require 'deploy-info/util'
14
+
15
+ module DeployInfo
16
+ # => This is the State controller. It manages State information
17
+ module State
18
+ extend self
19
+
20
+ ##############################
21
+ # => State Operations <= #
22
+ ##############################
23
+
24
+ attr_accessor :state
25
+
26
+ def state
27
+ @state ||= Util.parse_json_config(Config.state_file) || []
28
+ end
29
+
30
+ def find_state(app)
31
+ state.detect { |h| h[:name].casecmp(app).zero? }
32
+ end
33
+
34
+ def update_state(hash) # rubocop: disable AbcSize
35
+ # => Check if App Already Exists
36
+ existing = find_state(hash[:name])
37
+ if existing # => Update the Existing App
38
+ state.delete(existing)
39
+ audit_string = [DateTime.now, hash[:creator]].join(' - ')
40
+ existing[:last_modified] = existing[:last_modified].is_a?(Array) ? existing[:last_modified].take(5).unshift(audit_string) : [audit_string]
41
+ hash = existing
42
+ end
43
+
44
+ # => Update the State
45
+ state.push(hash)
46
+
47
+ # => Write Out the Updated State
48
+ write_state
49
+ end
50
+
51
+ # => Add Node to the State
52
+ def add_state(app, user, params) # rubocop: disable MethodLength, AbcSize
53
+ # => Create an App-State Object
54
+ (n = {}) && (n[:name] = app)
55
+ n[:created] = DateTime.now
56
+ n[:creator] = user
57
+ # => Parse our Field Values
58
+ %w(type).each do |opt|
59
+ n[opt.to_sym] = params[opt] if params[opt]
60
+ end
61
+ # => Parse our Booleans
62
+ %w(protected).each do |opt|
63
+ n[opt.to_sym] = true if params[opt] && %w(true 1).any? { |x| params[opt].to_s.casecmp(x).zero? }
64
+ end
65
+ # => Build the Updated State
66
+ update_state(n)
67
+ # => Return the Added App
68
+ find_state(node)
69
+ end
70
+
71
+ # => Remove App from the State
72
+ def delete_state(app)
73
+ # => Find the App
74
+ existing = find_state(app)
75
+ return 'App not present in state' unless existing
76
+ # => Delete the App from State
77
+ state.delete(existing)
78
+ # => Write Out the Updated State
79
+ write_state
80
+ # => Return the Deleted App
81
+ existing
82
+ end
83
+
84
+ def write_state
85
+ # => Sort & Unique State
86
+ state.sort_by! { |h| h[:name].downcase }.uniq!
87
+
88
+ # => Write Out the Updated State
89
+ Util.write_json_config(Config.state_file, state)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,64 @@
1
+ # Encoding: UTF-8
2
+ # rubocop: disable LineLength
3
+ #
4
+ # Gem Name:: deploy-info
5
+ # DeployInfo:: Util
6
+ #
7
+ # Copyright (C) 2016 Brian Dwyer - Intelligent Digital Services
8
+ #
9
+ # All rights reserved - Do Not Redistribute
10
+ #
11
+
12
+ require 'json'
13
+
14
+ module DeployInfo
15
+ # => Utility Methods
16
+ module Util
17
+ extend self
18
+
19
+ ########################
20
+ # => File I/O <= #
21
+ ########################
22
+
23
+ # => Define JSON Parser
24
+ def parse_json_config(file = nil, symbolize = true)
25
+ return unless file && ::File.exist?(file.to_s)
26
+ begin
27
+ ::JSON.parse(::File.read(file.to_s), symbolize_names: symbolize)
28
+ rescue JSON::ParserError
29
+ return
30
+ end
31
+ end
32
+
33
+ # => Define JSON Writer
34
+ def write_json_config(file, object)
35
+ return unless file && object
36
+ begin
37
+ File.open(file, 'w') { |f| f.write(JSON.pretty_generate(object)) }
38
+ end
39
+ end
40
+
41
+ #############################
42
+ # => Serialization <= #
43
+ #############################
44
+
45
+ def serialize(response)
46
+ # => Serialize Object into JSON Array
47
+ JSON.pretty_generate(response.map(&:name).sort_by(&:downcase))
48
+ end
49
+
50
+ def serialize_csv(csv)
51
+ # => Serialize a CSV String into an Array
52
+ return unless csv && csv.is_a?(String)
53
+ csv.split(',')
54
+ end
55
+
56
+ def serialize_revisions(branches, tags)
57
+ # => Serialize Branches/Tags into JSON Array
58
+ # => Branches = String, Tags = Key/Value
59
+ branches = branches.map(&:name).sort_by(&:downcase)
60
+ tags = tags.map(&:name).sort_by(&:downcase).reverse.map { |tag| { name: "Tag: #{tag}", value: tag } }
61
+ JSON.pretty_generate(branches + tags)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module DeployInfo
2
+ VERSION = '0.1.0'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deploy-info
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Dwyer
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-09-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: github_api
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.14'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mixlib-cli
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack-cache
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sinatra
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.4'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sinatra-contrib
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.4'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.12'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.12'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description:
140
+ email:
141
+ - bdwyer@IEEE.org
142
+ executables:
143
+ - deploy-info
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".gitignore"
148
+ - ".gitlab-ci.yml"
149
+ - ".rubocop.yml"
150
+ - Gemfile
151
+ - Gemfile.lock
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - bin/console
156
+ - bin/setup
157
+ - deploy-info.gemspec
158
+ - exe/deploy-info
159
+ - lib/deploy-info.rb
160
+ - lib/deploy-info/api.rb
161
+ - lib/deploy-info/cli.rb
162
+ - lib/deploy-info/config.rb
163
+ - lib/deploy-info/git.rb
164
+ - lib/deploy-info/helpers/configuration.rb
165
+ - lib/deploy-info/notifier.rb
166
+ - lib/deploy-info/state.rb
167
+ - lib/deploy-info/util.rb
168
+ - lib/deploy-info/version.rb
169
+ homepage: https://github.com/bdwyertech/deploy-info
170
+ licenses:
171
+ - MIT
172
+ metadata:
173
+ allowed_push_host: https://rubygems.org
174
+ post_install_message:
175
+ rdoc_options: []
176
+ require_paths:
177
+ - lib
178
+ required_ruby_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ required_rubygems_version: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ requirements: []
189
+ rubyforge_project:
190
+ rubygems_version: 2.6.6
191
+ signing_key:
192
+ specification_version: 4
193
+ summary: Deployment Notification and State Provider
194
+ test_files: []