configgin 0.12.0.pre

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: c0d8a6a8b00f54998849502a456de5a17b83b265
4
+ data.tar.gz: 9bbe965be9848864dbff2b6e3600d83805225347
5
+ SHA512:
6
+ metadata.gz: e21878032ef6a02a5647fd9e3ccee06d32e1b6f7caa39f4498b52f13fc133e7d72de1979536134e3f94af273d96f86c0ee8e4b65aa7f6e9ac4327f15a777e7ec
7
+ data.tar.gz: fa8e769269405ecb26fdf0338535d06c9cd88b17fdb34758b5ea6f02d5b5d6d0ccf484edbe0c9b16f88f10c5e7554b8ad2ad1eacffc7455c63a5309046539617
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ /output
2
+ /vendor/cache/
3
+ /vendor/sentinel
4
+ /.bundle/
5
+ configgin.go
data/.overcommit.yml ADDED
@@ -0,0 +1,8 @@
1
+ ---
2
+ PrePush:
3
+ SyncNotes:
4
+ enabled: true
5
+ command: ./vendor/github.com/hpe-cloud-garage/git-notary/hooks/pre-push/sync-notes
6
+ BranchHasNotes:
7
+ enabled: true
8
+ command: ./vendor/github.com/hpe-cloud-garage/git-notary/hooks/pre-push/branch-has-notes
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --backtrace
3
+ --format progress
data/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ inherit_from: .rubocop_todo.yml
2
+ AllCops:
3
+ Exclude:
4
+ - 'output/**/*'
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,48 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-10-14 10:11:25 -0700 using RuboCop version 0.31.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 4
9
+ Metrics/AbcSize:
10
+ Max: 26
11
+
12
+ # Offense count: 2
13
+ Metrics/CyclomaticComplexity:
14
+ Max: 10
15
+
16
+ # Offense count: 20
17
+ # Configuration parameters: AllowURI, URISchemes.
18
+ Metrics/LineLength:
19
+ Max: 108
20
+
21
+ # Offense count: 7
22
+ # Configuration parameters: CountComments.
23
+ Metrics/MethodLength:
24
+ Max: 28
25
+
26
+ # Offense count: 1
27
+ Metrics/PerceivedComplexity:
28
+ Max: 11
29
+
30
+ # Offense count: 10
31
+ # Cop supports --auto-correct.
32
+ # Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods.
33
+ Style/BlockDelimiters:
34
+ Enabled: false
35
+
36
+ # Offense count: 3
37
+ Style/ClassVars:
38
+ Enabled: false
39
+
40
+ # Offense count: 1
41
+ Style/EachWithObject:
42
+ Enabled: false
43
+
44
+ # Offense count: 1
45
+ # Cop supports --auto-correct.
46
+ # Configuration parameters: MaxLineLength.
47
+ Style/IfUnlessModifier:
48
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.7
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rspec'
7
+ gem 'rubocop'
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ configgin (0.1.0)
5
+ bosh-template (~> 1.3262.24.0)
6
+ deep_merge (~> 1.0.1)
7
+ mustache (~> 1.0)
8
+ rainbow (~> 2.0, != 2.2.1)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ ast (2.3.0)
14
+ bosh-template (1.3262.24.0)
15
+ semi_semantic (~> 1.2.0)
16
+ deep_merge (1.0.1)
17
+ diff-lcs (1.3)
18
+ mustache (1.0.5)
19
+ parser (2.4.0.0)
20
+ ast (~> 2.2)
21
+ powerpack (0.1.1)
22
+ rainbow (2.1.0)
23
+ rake (10.4.2)
24
+ rspec (3.5.0)
25
+ rspec-core (~> 3.5.0)
26
+ rspec-expectations (~> 3.5.0)
27
+ rspec-mocks (~> 3.5.0)
28
+ rspec-core (3.5.4)
29
+ rspec-support (~> 3.5.0)
30
+ rspec-expectations (3.5.0)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.5.0)
33
+ rspec-mocks (3.5.0)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.5.0)
36
+ rspec-support (3.5.0)
37
+ rubocop (0.48.1)
38
+ parser (>= 2.3.3.1, < 3.0)
39
+ powerpack (~> 0.1)
40
+ rainbow (>= 1.99.1, < 3.0)
41
+ ruby-progressbar (~> 1.7)
42
+ unicode-display_width (~> 1.0, >= 1.0.1)
43
+ ruby-progressbar (1.8.1)
44
+ semi_semantic (1.2.0)
45
+ unicode-display_width (1.2.1)
46
+
47
+ PLATFORMS
48
+ ruby
49
+
50
+ DEPENDENCIES
51
+ bundler (~> 1.14)
52
+ configgin!
53
+ rake (~> 10.0)
54
+ rspec
55
+ rubocop
56
+
57
+ BUNDLED WITH
58
+ 1.14.6
data/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ © Copyright 2016 Hewlett Packard Enterprise Development LP
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
4
+
5
+ http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
data/Makefile ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env make
2
+
3
+ GIT_ROOT:=$(shell git rev-parse --show-toplevel)
4
+
5
+ .PHONY: lint test dist
6
+
7
+ all: lint test dist
8
+
9
+ test:
10
+ ${GIT_ROOT}/make/test
11
+
12
+ lint:
13
+ ${GIT_ROOT}/make/lint
14
+
15
+ dist:
16
+ gem build ${GIT_ROOT}/configgin.gemspec
17
+
18
+ clean:
19
+ rm -rf output
data/NOTICE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2016 Hewlett Packard Enterprise, Inc. All rights reserved.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # configgin
2
+
3
+ A simple cli app in Ruby to generate configurations using [BOSH](https://bosh.io) ERB templates and
4
+ a BOSH spec, but also using configurations based on environment variables,
5
+ processed using a set of templates.
6
+
7
+ ## Usage
8
+
9
+ ```
10
+ Usage: configgin [options]
11
+ -j, --jobs file Job configuration JSON
12
+ -e, --env2conf file Environment to configuration templates YAML
13
+ ```
14
+
15
+ ## Examples
16
+
17
+ ### Example BOSH spec (bosh_spec.json)
18
+ ```json
19
+ {
20
+ "job": {
21
+ "name": "mysql",
22
+ "templates": [
23
+ {
24
+ "name": "mysql"
25
+ },
26
+ {
27
+ "name": "consul_agent"
28
+ }
29
+ ]
30
+ },
31
+ "networks": {
32
+ "default": {}
33
+ },
34
+ "properties": {
35
+ "acceptance_tests": {
36
+ "include_services": false,
37
+ "include_sso": false,
38
+ "nodes": 2
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ ### Example job configuration file (job_config.json)
45
+ ```json
46
+ {
47
+ "job_name": {
48
+ "base": "/tmp/bosh_spec.json",
49
+ "files": {
50
+ "/tmp/my_template.erb": "/tmp/output_file"
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### Example environment variable template file (env2.conf.yml)
57
+ ```yaml
58
+ ---
59
+ properties.acceptance_tests.nodes: "((TEST_NODE_COUNT))"
60
+ properties.uaa.scim.users: "'((TEST_VAR))'"
61
+ ```
62
+
63
+ ### Example template (my_template.erb)
64
+ ```erb
65
+ Hello, this is the users property: <%= p("uaa.scim.users") %>
66
+ ```
67
+
68
+ ### Example of using the tool
69
+ ```bash
70
+ TEST_VAR=foo
71
+ configgin \
72
+ -e ~/tmp/env2.conf.yml \
73
+ -j ~/tmp/job_config.json
74
+ ```
data/bin/configgin ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/configgin"
4
+
5
+ options = {}
6
+ parser = Cli.make_option_parser(options)
7
+
8
+ parser.parse!(ARGV)
9
+
10
+ begin
11
+ Cli.check_opts(options)
12
+ rescue ArgMissingError => e
13
+ STDERR.puts("missing argument: #{e}")
14
+ exit(1)
15
+ end
16
+
17
+ jobs = JSON.load(File.read(options[:jobs]))
18
+ templates = YAML.load_file(options[:env2conf])
19
+
20
+ jobs.each do |job, job_config|
21
+ base_config = JSON.load(File.read(job_config['base']))
22
+
23
+ job_config['files'].each do |infile, outfile|
24
+ begin
25
+ bosh_spec = EnvironmentConfigTransmogrifier.transmogrify(base_config,
26
+ templates,
27
+ secrets: '/etc/secrets')
28
+ rescue NonHashValueOverride => e
29
+ STDERR.puts e.to_s
30
+ STDERR.puts "Error generating #{job}: #{outfile} from #{infile}"
31
+ exit 1
32
+ end
33
+
34
+ Generate.generate(bosh_spec, infile, outfile)
35
+ end
36
+ end
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
data/configgin.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'configgin/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "configgin"
8
+ spec.version = Configgin::VERSION
9
+ spec.authors = ["hpcloud"]
10
+
11
+ spec.summary = "A simple cli app in Ruby to generate configurations using BOSH ERB templates and a BOSH spec."
12
+ spec.description = "A simple cli app in Ruby to generate configurations using BOSH ERB templates and a BOSH spec, but also using configurations based on environment variables, processed using a set of templates."
13
+ spec.homepage = "https://github.com/hpcloud/configgin"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ spec.bindir = "bin"
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.14"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+
25
+ spec.add_dependency 'bosh-template', '~> 1.3262.24.0'
26
+ spec.add_dependency 'rainbow', '~>2.0', '!=2.2.1'
27
+ spec.add_dependency 'deep_merge', '~> 1.0.1'
28
+ spec.add_dependency 'mustache', '~> 1.0'
29
+ end
data/lib/cli.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'optparse'
2
+ require 'generate'
3
+ require 'exceptions'
4
+
5
+ # Cli is a helper module for dealing with command line flags
6
+ module Cli
7
+ # Check options for any errors
8
+ #
9
+ # @param options [Hash] The options to check
10
+ def self.check_opts(options)
11
+ [:jobs, :env2conf].each do |key|
12
+ if options[key].nil? || options[key].empty?
13
+ raise ArgMissingError, key.to_s
14
+ end
15
+ end
16
+ end
17
+
18
+ # Make an option parser bound to the hash passed in.
19
+ #
20
+ # @param options [Hash] The hash that the options will be bound to on parse!
21
+ # @return [Object] The option parser that can be used.
22
+ def self.make_option_parser(options)
23
+ OptionParser.new do |opts|
24
+ opts.banner = 'Usage: configgin [options]'
25
+
26
+ # Job definition file
27
+ opts.on('-j', '--jobs file', 'Job definitions') do |j|
28
+ options[:jobs] = j
29
+ end
30
+
31
+ # Environment to configuration templates file
32
+ opts.on('-e', '--env2conf file',
33
+ 'Environment to configuration templates YAML') do |e|
34
+ options[:env2conf] = e
35
+ end
36
+ end
37
+ end
38
+ end
data/lib/configgin.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'cli'
2
+ require 'generate'
3
+ require 'environment_config_transmogrifier'
@@ -0,0 +1,5 @@
1
+ module Configgin
2
+
3
+ VERSION = "0.12.0.pre"
4
+
5
+ end
@@ -0,0 +1,132 @@
1
+ require 'yaml'
2
+ require 'mustache'
3
+ require 'shellwords'
4
+
5
+ # EnvironmentConfigTransmogrifier uses environment variables to generate config values
6
+ # for specific keys.
7
+ module EnvironmentConfigTransmogrifier
8
+ @@memoize_mustache = {}
9
+
10
+ # NoEscapeMustache does not escape these characters: & \ " < > '
11
+ class NoEscapeMustache < Mustache
12
+ # Disabling this cop because this is the function we need to override
13
+ # rubocop:disable MethodName
14
+ def escapeHTML(str)
15
+ str
16
+ end
17
+ end
18
+
19
+ # Processes the mustache templates and injects new keys into the configuration
20
+ #
21
+ # @return [Hash] Hash containing the updated configuration
22
+ def self.transmogrify(base_config, environment_templates, secrets: nil)
23
+ # build input hash for mustache
24
+ input_hash = ENV.to_hash
25
+
26
+ # load secrets
27
+ extendReplace(input_hash, secrets) if secrets && File.directory?(secrets)
28
+
29
+ # remove empty values
30
+ input_hash.reject! { |_, v| v.nil? || v.empty? }
31
+
32
+ # iterate through templates
33
+ environment_templates.each do |key, value|
34
+ # generate value from template
35
+
36
+ # we need to process the template at least once, even if it doesn't
37
+ # actually contain a mustache template, to get value types correctly;
38
+ # by default, all values are strings, because they come from the environment
39
+ # we need to unmarshall them using YAML.load
40
+ loop do
41
+ value = processMustacheTemplate(value, input_hash, key)
42
+ break unless value.respond_to?(:include?) && value.include?('((')
43
+ end
44
+
45
+ # inject value in huge json
46
+ inject_value(base_config, key.split('.'), value, key)
47
+ end
48
+
49
+ base_config['bootstrap'] = (base_config['index'] || 0) == 0
50
+
51
+ base_config
52
+ end
53
+
54
+ def self.processMustacheTemplate(value, input_hash, key)
55
+ val = @@memoize_mustache.fetch(value, {})[input_hash]
56
+ return val if val
57
+
58
+ delimiter = '{{=(( ))=}}'
59
+ begin
60
+ mustache_value = NoEscapeMustache.render("#{delimiter}#{value}", input_hash)
61
+ # replace new lines with double new lines for proper new-line YAML parsing
62
+ mustache_value = mustache_value.to_s.gsub("\n", "\n\n")
63
+ @@memoize_mustache[value] ||= {}
64
+ @@memoize_mustache[value][input_hash] = YAML.load(mustache_value)
65
+ rescue => e
66
+ msg = mustacheMessageFromError(e)
67
+ raise LoadYamlFromMustacheError, "Could not load config key '#{key}': #{msg}"
68
+ end
69
+ end
70
+
71
+ def self.mustacheMessageFromError(e)
72
+ lines = e.message.split(/\n/)
73
+ return 'No reason for failure given by mustache library' if lines.empty?
74
+ return lines.first if lines.size < 4
75
+
76
+ caret_line = lines[3]
77
+ caret_pos = caret_line.index('^')
78
+ return lines[0] + '.' unless caret_pos
79
+
80
+ delimiter = '{{=(( ))=}}'
81
+ actual_line = lines[2]
82
+ leading_junk = actual_line.lstrip.start_with?(delimiter) ? actual_line.index(delimiter) : 0
83
+ lines[0] + ": Error at or near position #{caret_pos - leading_junk} of template value."
84
+ end
85
+
86
+ def self.extendReplace(hash, path)
87
+ # This code assumes that 'path' points to a directory of files.
88
+ # The name of each file is the key into the hash, and the contents
89
+ # of the file are the value to enter, as-is. The order of the
90
+ # files in the directory does not matter.
91
+ Dir.glob(File.join(path, '*')).each do |file|
92
+ key = File.basename(file)
93
+ value = File.read(file)
94
+
95
+ # Write the collected information to the hash. This will
96
+ # overwrite, i.e. replace an existing value for that name. This
97
+ # means that the values found in 'path' have priority over the
98
+ # values already in the 'hash'. This is what we want for
99
+ # '/etc/secrets'
100
+ hash[key.upcase.tr('-', '_')] = value
101
+ end
102
+ end
103
+
104
+ def self.inject_value(hash, key_grams, value, original_key)
105
+ # if we only have 1 gram, we can set the value
106
+ if key_grams.size == 1
107
+ # If the new value is nil, and the old value was a hash, it's because
108
+ # somebody didn't provide a full default value; ignore it.
109
+ unless value.nil? && hash[key_grams[0]].is_a?(Hash)
110
+ hash[key_grams[0]] = value
111
+ end
112
+ return
113
+ end
114
+
115
+ # if there's more than one gram, keep going
116
+
117
+ # Initialize a hash if we're going deeper than what's currently available;
118
+ # sometimes we want to override when the old value is nil (i.e. no default)
119
+ # but the new value is a hash.
120
+ hash[key_grams[0]] = {} if hash[key_grams[0]].nil?
121
+ # error out if we're trying to override
122
+ # an existing value that's not a hash
123
+ unless hash[key_grams[0]].is_a?(Hash)
124
+ raise NonHashValueOverride, \
125
+ "Refusing to override non-hash value #{hash[key_grams[0]].inspect} " \
126
+ "with #{value.inspect}: '#{key_grams.join('.')}'" \
127
+ " - Complete key: '#{original_key}'"
128
+ end
129
+ # keep going deeper
130
+ inject_value(hash[key_grams[0]], key_grams.drop(1), value, original_key)
131
+ end
132
+ end
data/lib/exceptions.rb ADDED
@@ -0,0 +1,4 @@
1
+ class ArgMissingError < StandardError; end
2
+ class NonHashValueOverride < StandardError; end
3
+ class NoDataProvided < StandardError; end
4
+ class LoadYamlFromMustacheError < StandardError; end
data/lib/generate.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'bosh/template/renderer'
2
+ require 'json'
3
+
4
+ # Generate has methods for manipulating streams and generating configuration
5
+ # files using those streams.
6
+ module Generate
7
+ # Proces the given template using a provided spec and output filename
8
+ #
9
+ # @param bosh_spec [Hash] The input data as a hash
10
+ # @param input_file_path [String] The input filepath for the template
11
+ # @param output_file_path [String] The output filepath
12
+ def self.generate(bosh_spec, input_file_path, output_file_path, &_block)
13
+ # Make sure we're getting all the parameters we need
14
+ raise NoDataProvided if bosh_spec.nil?
15
+ raise NoInputFileProvided if input_file_path.nil?
16
+ raise NoOutputFileProvided if output_file_path.nil?
17
+
18
+ # Read the erb template
19
+ begin
20
+ perms = File.stat(input_file_path).mode
21
+ erb_template = ERB.new(File.read(input_file_path))
22
+ erb_template.filename = input_file_path
23
+ rescue Errno::ENOENT
24
+ raise "failed to read template file #{input_file_path}"
25
+ end
26
+
27
+ # Create a BOSH evaluation context
28
+ evaluation_context = Bosh::Template::EvaluationContext.new(bosh_spec)
29
+ # Process the Template
30
+ output = erb_template.result(evaluation_context.get_binding)
31
+
32
+ begin
33
+ # Open the output file
34
+ output_dir = File.dirname(output_file_path)
35
+ FileUtils.mkdir_p(output_dir)
36
+ out_file = File.open(output_file_path, 'w')
37
+ # Write results to the output file
38
+ out_file.write(output)
39
+ # Set the appropriate permissions on the output file
40
+ out_file.chmod(perms)
41
+ rescue Errno::ENOENT, Errno::EACCES => e
42
+ out_file = nil
43
+ raise "failed to open output file #{output_file_path}: #{e}"
44
+ ensure
45
+ out_file.close unless out_file.nil?
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -o errexit
4
+
5
+ if [ "$(uname)" == "Darwin" ]; then
6
+ DOCKER_RUNTIME=${DOCKER_RUNTIME:-'helioncf/hcf-pipeline-ruby-bosh'}
7
+
8
+ # We need to mount the enclosing repo in case we are just a submodule
9
+ # (still doesn't support being a nested submodule though)
10
+ ROOT=${PWD}
11
+ if [ -f .git ]; then cd ..; fi
12
+ GIT_ROOT=$(git rev-parse --show-toplevel)
13
+ cd ${ROOT}
14
+
15
+ WORK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
16
+
17
+ docker run \
18
+ --rm \
19
+ --volume ${GIT_ROOT}:${GIT_ROOT} \
20
+ --workdir ${WORK_DIR} \
21
+ --entrypoint bash \
22
+ ${DOCKER_RUNTIME} \
23
+ -l -c "export RBENV_VERSION=2.1.7 && ${BASH_SOURCE[1]}"
24
+
25
+ exit
26
+ fi
@@ -0,0 +1,20 @@
1
+ #!/bin/sh
2
+
3
+ test -n "${XTRACE}" && set -o xtrace
4
+
5
+ set -o errexit -o nounset
6
+
7
+ GIT_ROOT=${GIT_ROOT:-$(git rev-parse --show-toplevel)}
8
+ GIT_DESCRIBE=${GIT_DESCRIBE:-$(git describe --tags --long)}
9
+ GIT_BRANCH=${GIT_BRANCH:-$(git name-rev --name-only HEAD)}
10
+
11
+ GIT_TAG=${GIT_TAG:-$(echo ${GIT_DESCRIBE} | awk -F - '{ print $1 }' )}
12
+ GIT_COMMITS=${GIT_COMMITS:-$(echo ${GIT_DESCRIBE} | awk -F - '{ print $2 }' )}
13
+ GIT_SHA=${GIT_SHA:-$(echo ${GIT_DESCRIBE} | awk -F - '{ print $3 }' )}
14
+
15
+ ARTIFACT_NAME=${ARTIFACT_NAME:-$(basename $(git config --get remote.origin.url) .git | sed s/^hcf-//)}
16
+ ARTIFACT_VERSION=${GIT_TAG}+${GIT_COMMITS}.${GIT_SHA}
17
+
18
+ APP_VERSION=${ARTIFACT_NAME}-${ARTIFACT_VERSION}
19
+
20
+ set +o errexit +o nounset +o xtrace
data/make/lint ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -o errexit
4
+
5
+ GIT_ROOT=${GIT_ROOT:-$(git rev-parse --show-toplevel)}
6
+ . ${GIT_ROOT}/make/include/darwin-support
7
+
8
+ bundle package
9
+ bundle exec rubocop --fail-level=error
data/make/test ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -o errexit
4
+
5
+ GIT_ROOT=${GIT_ROOT:-$(git rev-parse --show-toplevel)}
6
+ . ${GIT_ROOT}/make/include/darwin-support
7
+
8
+ bundle package
9
+ bundle exec rspec "${@}"
@@ -0,0 +1,2 @@
1
+ auto/**
2
+ *.tex
@@ -0,0 +1,21 @@
1
+
2
+ The MIT License (MIT)
3
+ Copyright © 2016 Chris Olstrom <chris@olstrom.com>
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.
@@ -0,0 +1,140 @@
1
+ #+TITLE: git-notary
2
+ #+SUBTITLE: a versioning experiment for git
3
+ #+LATEX: \pagebreak
4
+
5
+ * Overview
6
+
7
+ ~git-notary~ generates canonical version tags from versioning notes.
8
+
9
+ ** Why would I want this?
10
+
11
+ ~git-notary~ may be helpful if you want to use Semantic Versioning in a project
12
+ with many contributors and some manner of branch-oriented workflow. Tracking
13
+ versioning information with a ~VERSION~ file seems like a great idea, but has
14
+ some quirks.
15
+
16
+ ** An Example Scenario
17
+
18
+ Consider the following (simplified) scenario:
19
+
20
+ #+BEGIN_EXAMPLE
21
+ ,* e44e210 - (HEAD -> develop) Merge branch 'bar' into develop
22
+ |\
23
+ | * e1793f3 - (bar) PATCH
24
+ | * f231d3b - MAJOR
25
+ | * 5c69653 - MAJOR
26
+ ,* | 67543e1 - Merge branch 'foo' into develop
27
+ |\ \
28
+ | |/
29
+ |/|
30
+ | * ea81623 - (foo) MAJOR
31
+ | * 8b773db - PATCH
32
+ | * 6613b79 - MINOR
33
+ |/
34
+ ,* 21c36f3 - (master) MINOR
35
+ ,* 64357c2 - MINOR
36
+ ,* 9ebfd7d - MINOR
37
+ ,* cc5d832 - PATCH
38
+ ,* ebc851f - MINOR
39
+ ,* a75790f - PATCH
40
+ ,* 572a9e8 - MAJOR
41
+ ,* a990127 - (tag: 0.0.0) INITIAL
42
+ #+END_EXAMPLE
43
+
44
+ In this example, two branches (~foo~ and ~bar~) were created from ~master~
45
+ (~21c36f3~). Both branches know that ~1.4.0~ is the latest tag (at the time they
46
+ branched). Let's assume these branches do not conflict with each other.
47
+
48
+ With a ~VERSION~ file, a project generally chooses one of two places to update it:
49
+
50
+ - Updates occur in the branch. In this case, once either branch is merged, the
51
+ other is in conflict with it.
52
+ - Updates occur in the trunk. In this case, the trunk now contains code that did
53
+ not originate in a branch. Again, the first merged is safe, but the other is
54
+ in a conflicting state.
55
+
56
+ If ~foo~ merges first, the expected version post-merge is ~2.0.0~.
57
+
58
+ If ~bar~ merges first, the expected version is ~3.0.1~.
59
+
60
+ At ~e44e210~ (~HEAD~ of ~develop~), the final version should be ~4.0.1~, but if
61
+ the merge order were reversed, it should be ~4.0.0~. This gets worse as the
62
+ number of active branches increases.
63
+
64
+ * Assumptions
65
+
66
+ - Versioning is important.
67
+ - Versions should communicate scope of change.
68
+ - Humans can signal the scope of their own changes.
69
+ - Machines can figure out the rest.
70
+
71
+ * Installation
72
+
73
+ ** Install via RubyGems
74
+
75
+ ~gem install --no-wrapper git-notary~
76
+
77
+ ** Manual Installation
78
+
79
+ Download the latest release of ~git-notary~ and place it somewhere in your ~$PATH~.
80
+
81
+ #+LATEX: \pagebreak
82
+
83
+ * Usage
84
+
85
+ ** Add new versioning information
86
+
87
+ #+BEGIN_SRC shell
88
+ git-notary new <version> [object] [namespace]
89
+ #+END_SRC
90
+
91
+ Where <version> is one of (major, minor, patch).
92
+
93
+ ** Undo a version
94
+
95
+ #+BEGIN_SRC shell
96
+ git-notary undo [object] [namespace]
97
+ #+END_SRC
98
+
99
+ ** Fetch versioning notes
100
+
101
+ #+BEGIN_SRC shell
102
+ git-notary fetch [remote] [namespace]
103
+ #+END_SRC
104
+
105
+ ** Fetch and merge versioning notes
106
+
107
+ #+BEGIN_SRC shell
108
+ git-notary pull [remote] [namespace] [merge-strategy]
109
+ #+END_SRC
110
+
111
+ ** Push versioning notes
112
+
113
+ #+BEGIN_SRC shell
114
+ git-notary push [remote] [namespace]
115
+ #+END_SRC
116
+
117
+ ** Extract Notes
118
+
119
+ #+BEGIN_SRC shell
120
+ git-notary notes [branch] [base] [namespace]
121
+ #+END_SRC
122
+
123
+ ** Compute Versions from Notes
124
+
125
+ #+BEGIN_SRC shell
126
+ git-notary notes | git-notary versions [initial]
127
+ #+END_SRC
128
+
129
+ ** Generate Tags from Versions
130
+
131
+ #+BEGIN_SRC shell
132
+ git-notary notes | git-notary versions | git-notary tags [--apply]
133
+ #+END_SRC
134
+
135
+ * License
136
+
137
+ ~git-notary~ is available under the [[https://tldrlegal.com/license/mit-license][MIT License]]. See ~LICENSE.txt~ for the full text.
138
+
139
+ * Contributors
140
+ - [[https://colstrom.github.io/][Chris Olstrom]] | [[mailto:chris@olstrom.com][e-mail]] | [[https://twitter.com/ChrisOlstrom][Twitter]]
@@ -0,0 +1,262 @@
1
+ #!/bin/sh
2
+
3
+ GIT_NOTARY_VERSION=2.3.1
4
+ GIT_NOTARY_NAMESPACE=${GIT_NOTARY_NAMESPACE:-'versioning'}
5
+
6
+ # notes [branch] [base] [namespace]
7
+ notes() {
8
+ BRANCH=${1-'develop'}
9
+ BASE=${2:-$(git describe --tags --abbrev=0)}
10
+ NAMESPACE=${3:-${GIT_NOTARY_NAMESPACE}}
11
+
12
+ git rev-list --topo-order ${BASE}..${BRANCH} --reverse | while read OBJECT; do
13
+ printf "${OBJECT} "
14
+ git notes --ref=${NAMESPACE} show ${OBJECT} 2> /dev/null || echo
15
+ done | grep -E '(MAJOR|MINOR|PATCH)$'
16
+ }
17
+
18
+ # squash
19
+ squash() {
20
+ while read OBJECT_CHANGE; do
21
+ OBJECT=$(echo ${OBJECT_CHANGE} | awk '{ print $1 }')
22
+ CHANGE=$(echo ${OBJECT_CHANGE} | awk '{ print $2 }')
23
+
24
+ case ${CHANGE} in
25
+ MAJOR)
26
+ RESULT=MAJOR;;
27
+ MINOR)
28
+ test "${RESULT}" != MAJOR && RESULT=MINOR;;
29
+ PATCH)
30
+ test -z "${RESULT}" && RESULT=PATCH;;
31
+ esac
32
+ done
33
+
34
+ test ! -z "${RESULT}" && echo ${OBJECT} ${RESULT}
35
+ }
36
+
37
+ # squeeze <up|down>
38
+ squeeze() {
39
+ case ${1} in
40
+ d|down|f|first|o|old*)
41
+ DIRECTION=DOWN;;
42
+ u|up|l|last|n|new*)
43
+ DIRECTION=UP;;
44
+ *)
45
+ echo 'git-notary squeeze requires a direction (up or down)' >&2
46
+ exit 23;;
47
+ esac
48
+
49
+ while read OBJECT_CHANGE; do
50
+ OBJECT=$(echo ${OBJECT_CHANGE} | awk '{ print $1 }')
51
+ CHANGE=$(echo ${OBJECT_CHANGE} | awk '{ print $2 }')
52
+
53
+ if test "${CHANGE}" != "${LAST_CHANGE}"; then
54
+ case ${DIRECTION} in
55
+ DOWN)
56
+ echo ${OBJECT} ${CHANGE};;
57
+ UP)
58
+ test ! -z "${LAST_OBJECT}" && echo ${LAST_OBJECT} ${LAST_CHANGE};;
59
+ esac
60
+ fi
61
+
62
+ LAST_OBJECT=${OBJECT}
63
+ LAST_CHANGE=${CHANGE}
64
+ done
65
+
66
+ test "${DIRECTION}" = UP && echo ${LAST_OBJECT} ${LAST_CHANGE}
67
+ }
68
+
69
+ # versions [initial]
70
+ versions() {
71
+ set -o errexit
72
+ VERSION=${1:-$(git describe --tags --abbrev=0)}
73
+
74
+ MAJOR=$(echo ${VERSION} | awk -F . '{ print $1 }')
75
+ MINOR=$(echo ${VERSION} | awk -F . '{ print $2 }')
76
+ PATCH=$(echo ${VERSION} | awk -F . '{ print $3 }')
77
+
78
+ next() {
79
+ echo ${1} + 1 | bc
80
+ }
81
+
82
+ while read OBJECT_CHANGE; do
83
+ OBJECT=$(echo ${OBJECT_CHANGE} | awk '{ print $1 }')
84
+ CHANGE=$(echo ${OBJECT_CHANGE} | awk '{ print $2 }')
85
+
86
+ case ${CHANGE} in
87
+ MAJOR)
88
+ MAJOR=$(next ${MAJOR})
89
+ MINOR=0
90
+ PATCH=0
91
+ ;;
92
+ MINOR)
93
+ MINOR=$(next ${MINOR})
94
+ PATCH=0
95
+ ;;
96
+ PATCH)
97
+ PATCH=$(next ${PATCH})
98
+ ;;
99
+ esac
100
+
101
+ VERSION=${MAJOR}.${MINOR}.${PATCH}
102
+ echo ${OBJECT} ${VERSION}
103
+ done
104
+ }
105
+
106
+ # tags [--apply]
107
+ tags() {
108
+ while read OBJECT_TAG; do
109
+ OBJECT=$(echo ${OBJECT_TAG} | awk '{ print $1 }')
110
+ TAG=$(echo ${OBJECT_TAG} | awk '{ print $2 }')
111
+
112
+ if test "${1}" = '--apply'; then
113
+ git tag ${TAG} ${OBJECT}
114
+ else
115
+ echo git tag ${TAG} ${OBJECT}
116
+ fi
117
+ done
118
+ }
119
+
120
+ # fetch [remote] [namespace]
121
+ fetch() {
122
+ FORCE=""
123
+ if test "${1:-}" = "--force"; then
124
+ shift
125
+ FORCE="+"
126
+ fi
127
+ REMOTE=${1:-'origin'}
128
+ NAMESPACE=${2:-${GIT_NOTARY_NAMESPACE}}
129
+
130
+ git fetch ${REMOTE} ${FORCE}refs/notes/${NAMESPACE}:refs/notes/${NAMESPACE}
131
+ }
132
+
133
+ # pull [remote] [namespace] [strategy]
134
+ pull() {
135
+ REMOTE=${1:-'origin'}
136
+ NAMESPACE=${2:-${GIT_NOTARY_NAMESPACE}}
137
+ STRATEGY=${3:-'theirs'}
138
+
139
+ git fetch ${REMOTE} refs/notes/${NAMESPACE}
140
+ env GIT_NOTES_REF=refs/notes/${NAMESPACE} git notes merge -s ${STRATEGY} FETCH_HEAD
141
+ }
142
+
143
+ # push [remote] [namespace]
144
+ push() {
145
+ REMOTE=${1:-'origin'}
146
+ NAMESPACE=${2:-${GIT_NOTARY_NAMESPACE}}
147
+
148
+ git push --no-verify ${REMOTE} refs/notes/${NAMESPACE}
149
+ }
150
+
151
+ # new <major|minor|patch> [object] [namespace]
152
+ new() {
153
+ CHANGE=$(echo ${1} | tr [:lower:] [:upper:])
154
+ OBJECT=${2:-HEAD}
155
+ NAMESPACE=${3:-${GIT_NOTARY_NAMESPACE}}
156
+
157
+ if echo ${CHANGE} | grep -qE '^(MAJOR|MINOR|PATCH)$'; then
158
+ git notes --ref=${NAMESPACE} add --message ${CHANGE} ${OBJECT}
159
+ else
160
+ echo MAJOR MINOR and PATCH are valid. ${CHANGE} is not.
161
+ exit 23
162
+ fi
163
+ }
164
+
165
+ # delta (--squash) [object] [base] [namespace]
166
+ delta() {
167
+ if test "${1}" = '--squash'; then
168
+ SQUASH=true
169
+ shift
170
+ fi
171
+
172
+ OBJECT=${1:-HEAD}
173
+ BASE=${2:-$(git describe --tags --abbrev=0)}
174
+ NAMESPACE=${3:-${GIT_NOTARY_NAMESPACE}}
175
+
176
+ if test "${SQUASH}" = 'true'; then
177
+ NEW=$(git-notary notes ${OBJECT} ${BASE} ${NAMESPACE} | git-notary squash | git-notary versions | awk '{ print $2 }')
178
+ else
179
+ NEW=$(git-notary notes ${OBJECT} ${BASE} ${NAMESPACE} | git-notary versions | tail -1 | awk '{ print $2 }')
180
+ fi
181
+
182
+ LATEST_TAG_ON_BASE=$(git describe --tags --abbrev=0 ${BASE})
183
+ OLD=${LATEST_TAG_ON_BASE:-'0.0.0'}
184
+ echo "${OLD} -> ${NEW}"
185
+ }
186
+
187
+ # undo [object] [namespace]
188
+ undo() {
189
+ OBJECT=${1:-HEAD}
190
+ NAMESPACE=${2:-${GIT_NOTARY_NAMESPACE}}
191
+
192
+ git notes --ref=${NAMESPACE} remove ${OBJECT}
193
+ }
194
+
195
+ # version
196
+ version() {
197
+ echo "git-notary ${GIT_NOTARY_VERSION}"
198
+ }
199
+
200
+ # help
201
+ help() {
202
+ cat <<EOF
203
+ $(version)
204
+ usage:
205
+ git-notary new <major|minor|patch> [object] [namespace]
206
+ git-notary undo [object] [namespace]
207
+ git-notary delta [--squash] [object] [base] [namespace]
208
+
209
+ git-notary fetch [remote] [namespace]
210
+ git-notary push [remote] [namespace]
211
+
212
+ git-notary notes [branch] [base] [namespace]
213
+ git-notary versions [initial]
214
+ git-notary tags [--apply]
215
+ EOF
216
+ }
217
+
218
+ # notary <command> [args]
219
+ notary() {
220
+ COMMAND=${1}
221
+ shift
222
+ case ${COMMAND} in
223
+ N|notes)
224
+ notes ${@};;
225
+ V|versions)
226
+ versions ${@};;
227
+ T|tags)
228
+ tags ${@};;
229
+ S|squash)
230
+ squash ${@};;
231
+ Z|squeeze)
232
+ squeeze ${@};;
233
+ n|new)
234
+ new ${@};;
235
+ u|undo)
236
+ undo ${@};;
237
+ d|delta)
238
+ delta ${@};;
239
+ P|push)
240
+ push ${@};;
241
+ f|fetch)
242
+ fetch ${@};;
243
+ fm|fetch-merge|pull)
244
+ pull ${@};;
245
+ M|major)
246
+ new MAJOR ${@};;
247
+ m|minor)
248
+ new MINOR ${@};;
249
+ p|patch)
250
+ new PATCH ${@};;
251
+ v|version|-v|--version)
252
+ version;;
253
+ h|help|-h|--help)
254
+ help;;
255
+ *)
256
+ help
257
+ exit 1
258
+ ;;
259
+ esac
260
+ }
261
+
262
+ notary "${@:-}"
@@ -0,0 +1,11 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = 'git-notary'
3
+ gem.version = `git describe --tags --abbrev=0`.chomp
4
+ gem.license = 'MIT'
5
+ gem.author = 'Chris Olstrom'
6
+ gem.email = 'chris@olstrom.com'
7
+ gem.homepage = 'https://github.com/colstrom/git-notary'
8
+ gem.summary = 'generates canonical version tags from versioning notes'
9
+ gem.files = `git ls-files`.split("\n")
10
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
11
+ end
@@ -0,0 +1,12 @@
1
+ #!/bin/sh
2
+
3
+ while read LOCAL_REF LOCAL_SHA REMOTE_REF REMOTE_SHA; do
4
+ if git-notary notes ${LOCAL_SHA} develop > /dev/null; then
5
+ BRANCH_HAS_NOTES=true
6
+ else
7
+ BRANCH_HAS_NOTES=false
8
+ break
9
+ fi
10
+ done
11
+
12
+ test ${BRANCH_HAS_NOTES} = true
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ set -o errexit
4
+
5
+ git-notary pull
6
+ git-notary push
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: configgin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.12.0.pre
5
+ platform: ruby
6
+ authors:
7
+ - hpcloud
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-05-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bosh-template
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.3262.24.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3262.24.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rainbow
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ - - "!="
63
+ - !ruby/object:Gem::Version
64
+ version: 2.2.1
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '2.0'
72
+ - - "!="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.2.1
75
+ - !ruby/object:Gem::Dependency
76
+ name: deep_merge
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 1.0.1
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 1.0.1
89
+ - !ruby/object:Gem::Dependency
90
+ name: mustache
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.0'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.0'
103
+ description: A simple cli app in Ruby to generate configurations using BOSH ERB templates
104
+ and a BOSH spec, but also using configurations based on environment variables, processed
105
+ using a set of templates.
106
+ email:
107
+ executables:
108
+ - configgin
109
+ - setup
110
+ extensions: []
111
+ extra_rdoc_files: []
112
+ files:
113
+ - ".gitignore"
114
+ - ".overcommit.yml"
115
+ - ".rspec"
116
+ - ".rubocop.yml"
117
+ - ".rubocop_todo.yml"
118
+ - ".ruby-version"
119
+ - Gemfile
120
+ - Gemfile.lock
121
+ - LICENSE.md
122
+ - Makefile
123
+ - NOTICE
124
+ - README.md
125
+ - bin/configgin
126
+ - bin/setup
127
+ - configgin.gemspec
128
+ - lib/cli.rb
129
+ - lib/configgin.rb
130
+ - lib/configgin/version.rb
131
+ - lib/environment_config_transmogrifier.rb
132
+ - lib/exceptions.rb
133
+ - lib/generate.rb
134
+ - make/include/darwin-support
135
+ - make/include/versioning
136
+ - make/lint
137
+ - make/test
138
+ - vendor/github.com/hpe-cloud-garage/git-notary/.gitignore
139
+ - vendor/github.com/hpe-cloud-garage/git-notary/LICENSE.txt
140
+ - vendor/github.com/hpe-cloud-garage/git-notary/README.org
141
+ - vendor/github.com/hpe-cloud-garage/git-notary/bin/git-notary
142
+ - vendor/github.com/hpe-cloud-garage/git-notary/git-notary.gemspec
143
+ - vendor/github.com/hpe-cloud-garage/git-notary/hooks/pre-push/branch-has-notes
144
+ - vendor/github.com/hpe-cloud-garage/git-notary/hooks/pre-push/sync-notes
145
+ homepage: https://github.com/hpcloud/configgin
146
+ licenses: []
147
+ metadata: {}
148
+ post_install_message:
149
+ rdoc_options: []
150
+ require_paths:
151
+ - lib
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ required_rubygems_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">"
160
+ - !ruby/object:Gem::Version
161
+ version: 1.3.1
162
+ requirements: []
163
+ rubyforge_project:
164
+ rubygems_version: 2.6.10
165
+ signing_key:
166
+ specification_version: 4
167
+ summary: A simple cli app in Ruby to generate configurations using BOSH ERB templates
168
+ and a BOSH spec.
169
+ test_files: []