modulesync 0.0.1

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: 5b33cdfbc0df1b30570ffadbd78e6bbcec9ba8b6
4
+ data.tar.gz: 5044a6754a320ec00e0ebf4bb7cba71087da9e02
5
+ SHA512:
6
+ metadata.gz: 529d0ed35ec73c722cb607980133637851e1cfda52d564542ec3d0393bae5bcce62a5c72dff96b430654c2fff69ee263c17f4d3a9572924d3cd1342f89aacf74
7
+ data.tar.gz: 563cf2c60a67b435a9ff7481f37288236166ea1fa66d30087becf15ef932335ceda65685aecfd8d8625172a4594e8265a34ece2c2ab4d6fe555cf85099d78ddf
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ modules/
2
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source ENV['GEM_SOURCE'] || 'https://rubygems.org'
2
+
3
+ gem 'git'
data/Gemfile.lock ADDED
@@ -0,0 +1,10 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ git (1.2.7)
5
+
6
+ PLATFORMS
7
+ ruby
8
+
9
+ DEPENDENCIES
10
+ git
data/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Puppet Module Sync
2
+
3
+ Copyright (C) 2014 Puppet Labs Inc
4
+
5
+ Puppet Labs can be contacted at: info@puppetlabs.com
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,220 @@
1
+ ModuleSync
2
+ ===========
3
+
4
+ Table of Contents
5
+ -----------------
6
+
7
+ 1. [Usage TLDR](#usage-tldr)
8
+ 2. [Overview](#overview)
9
+ 3. [How it works](#how-it-works)
10
+ 4. [Installing](#installing)
11
+ 5. [Workflow](#workflow)
12
+ 6. [The Templates](#the-templates)
13
+
14
+ Usage TLDR
15
+ ----------
16
+
17
+ ```
18
+ gem install modulesync
19
+ msync --help
20
+ ```
21
+
22
+ Overview
23
+ --------
24
+
25
+ ModuleSync was written as a simple script with ERB templates to help the
26
+ Puppet Labs module engineers manage the zoo of Puppet modules on GitHub, and
27
+ has now been restructured and generalized to be used within other
28
+ organizations. Puppet modules within an organization tend to have a number of
29
+ meta-files that are identical or very similar between modules, such as the
30
+ Gemfile, .travis.yml, .gitignore, or spec\_helper.rb. If a file needs to
31
+ change in one module, it likely needs to change in the same way in every other
32
+ module that the organization manages.
33
+
34
+ One approach to this problem is to use sed in a bash for loop on the modules to
35
+ make a single change across every module. This approach falls short if there is
36
+ a single file that is purposefully different than the others, but still needs
37
+ to be managed. Moreover, this approach does not help if two files are
38
+ structured differently but need to be changed with the same meaning; for
39
+ instance, if the .travis.yml of one module uses a list of environments to
40
+ include, and another uses a matrix of includes with a list of excludes, adding
41
+ a test environment to both modules will require entirely different approaches.
42
+
43
+ ModuleSync provides the advantage of defining a standard template for each
44
+ file to follow, so it becomes clear what a file is supposed to look like. Two
45
+ files with the same semantics should also have the same syntax. A difference
46
+ between two files should have clear reasons, and old cruft should not be left
47
+ in files of one module as the files of another module march forward.
48
+
49
+ Another advantage of ModuleSync is the ability to run in no-op mode, which
50
+ makes local changes and shows the diffs, but does not make permanent changes in
51
+ the remote repository.
52
+
53
+ How It Works
54
+ ------------
55
+
56
+ ModuleSync is a gem that uses the GitHub workflow to clone, update, and push module
57
+ repositories. It expects to be activated from a directory containing
58
+ configuration for modulesync and the modules, or you can pass it the location
59
+ of this configuration directory. [The configuration for the Puppet Labs
60
+ modules](https://github.com/puppetlabs/modulesync\_configs), can be used as an
61
+ example for your own configuration. The configuration directory contains a
62
+ directory called moduleroot which mirrors the structure of a module. The files
63
+ in the moduleroot could be flat files or ERB templates. The templates are
64
+ rendered using values from a file called config\_defaults.yml in the root (not
65
+ moduleroot) of the configuration directory. The default values can be
66
+ overridden or extended by adding a file called .sync.yml to the module itself.
67
+ This allows us to, for example, have a set of "required" gems that are added
68
+ to all Gemfiles, and a set of "optional" gems that a single module might add.
69
+
70
+ The list of modules to manage is in managed\_modules.yml in the configuration
71
+ directory. This lists just the GitHub names of the modules to be managed.
72
+
73
+ ModuleSync can be called from the command line with parameters to change the
74
+ branch you're working on or the remote to clone from and push to. You can also
75
+ define these parameters in a file named modulesync.yml in the configuration
76
+ directory.
77
+
78
+ Installing
79
+ ----------
80
+
81
+ ```
82
+ gem install modulesync
83
+ ```
84
+
85
+ For developers:
86
+
87
+ ```
88
+ gem build modulesync.gemspec
89
+ gem install modulesync-*.gem
90
+ ```
91
+
92
+ Workflow
93
+ --------
94
+
95
+ ### Default mode
96
+
97
+ With no additional arguments, ModuleSync clones modules from the puppetlabs
98
+ github organization and pushes to the master branch.
99
+
100
+ #### Make changes
101
+
102
+ Make changes to a file in the moduleroot. For sanity's sake you should commit
103
+ and push these changes, but in this mode the update will be rendered from the
104
+ state of the files locally. Run `msync update` from the root of the
105
+ configuration directory (not moduleroot), or use -c <relative path> to point
106
+ it to the location of the configuration directory.
107
+
108
+ #### Dry-run
109
+
110
+ Do a dry-run to see what files will be changed, added and removed. This clones
111
+ the modules to `modules/<namespace>-<modulename>` in the current working, or if
112
+ the modules are already cloned, does an effective `git fetch origin; git
113
+ checkout master; git reset --hard origin/master` on the modules. Don't run
114
+ modulesync if the current working directory contains a modules/ directory with
115
+ changes you want to keep. The dry-run makes local changes there, but does not
116
+ commit or push changes. It is still destructive in that it overwrites local
117
+ changes.
118
+
119
+ ```
120
+ msync update --noop
121
+ ```
122
+
123
+ #### Damage mode
124
+
125
+ Make changes for real and push them back to master. This operates on the
126
+ pre-cloned modules from the dry-run or clones them fresh if the modules aren't
127
+ found.
128
+
129
+ ```
130
+ msync update
131
+ ```
132
+
133
+ #### Automating Updates
134
+
135
+ You can install a pre-push git hook to automatically clone, update, and push
136
+ modules upon pushing changes to the configuration directory. This does not
137
+ include a noop mode.
138
+
139
+ ```
140
+ msync hook activate
141
+ ```
142
+
143
+ If you have activated the hook but want to make changes to the configuration
144
+ directory (such as changes to managed_modules.yml or modulesync.yml) without
145
+ touching the modules, you can deactivate the hook.
146
+
147
+ ```
148
+ msync hook deactivate
149
+ ```
150
+
151
+ ### Using Forks and Non-master branches
152
+
153
+ The default functionality is to run ModuleSync on the puppetlabs modules, but
154
+ you can use this on your own organization's modules. This functionality also
155
+ applies if you want to work on a fork of the puppetlabs modules or work on a
156
+ non-master branch of any organization's modules. ModuleSync does not support
157
+ cloning from one remote and pushing to another, you are expected to fork
158
+ manually. It does not yet support automating pull requests (coming soon).
159
+
160
+ #### Dry-run
161
+
162
+ If you dry-run before doing the live update, you need to specify what namespace
163
+ to clone from because the live update will not re-clone if the modules are
164
+ already cloned. The namespace should be your fork, not the upstream module. The
165
+ format should be the SSH or HTTP prefix of the full URL minus the module name
166
+ itself.
167
+
168
+ ```
169
+ msync update -n git@github.com:puppetlabs --noop
170
+ ```
171
+
172
+ #### Damage mode
173
+
174
+ You don't technically need to specify the namespace if the modules are already
175
+ cloned from the dry-run, but it doesn't hurt. You do need to specify the
176
+ namespace if the modules are not pre-cloned. You need to specify a branch to
177
+ push to if you are not pushing to master.
178
+
179
+ ```
180
+ msync update -n git@github.com:puppetlabs -b sync_branch
181
+ ```
182
+
183
+ #### Configuring ModuleSync defaults
184
+
185
+ If you're not using the puppetlabs modules or only ever pushing to a fork of
186
+ them, then specifying the namespace and branch every time you use ModuleSync
187
+ probably seems excessive. You can create a file called modulesync.yml in the
188
+ configuration directory that provides these arguments automatically. This file
189
+ has a form such as:
190
+
191
+ ```
192
+ ---
193
+ namespace: mygithubusername
194
+ branch: modulesyncbranch
195
+ ```
196
+
197
+ Then you can run ModuleSync without extra arguments:
198
+
199
+ ```
200
+ msync update --noop
201
+ msync update
202
+ ```
203
+
204
+ #### Automating updates
205
+
206
+ If you install a git hook, you need to tell it what remote and branch to push
207
+ to. This may not work properly if you already have the modules cloned from a
208
+ different remote. The hook will also look in modulesync.yml for default
209
+ arguments.
210
+
211
+ ```
212
+ msync hook activate -n git@github.com:puppetlabs -b sync_branch
213
+ ```
214
+
215
+ The Templates
216
+ -------------
217
+
218
+ See the [modulesync\_configs](https://github.com/puppetlabs/modulesync_configs)
219
+ repository for an explanation of the templates that Puppet Labs uses on its
220
+ modules.
data/bin/msync ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $:.unshift(lib) unless $:.include?(lib)
5
+
6
+ require 'modulesync'
7
+
8
+ ModuleSync.run(ARGV)
@@ -0,0 +1,81 @@
1
+ require 'optparse'
2
+ require 'modulesync/constants'
3
+ require 'modulesync/util'
4
+
5
+ module ModuleSync
6
+ class CLI
7
+ include Constants
8
+
9
+ def defaults
10
+ {
11
+ :namespace => 'puppetlabs',
12
+ :branch => 'master',
13
+ :managed_modules_conf => 'managed_modules.yml',
14
+ :configs => '.',
15
+ }
16
+ end
17
+
18
+ def commands_available
19
+ [
20
+ 'update',
21
+ 'hook',
22
+ ]
23
+ end
24
+
25
+ def fail(message)
26
+ puts @options[:help]
27
+ puts message
28
+ exit
29
+ end
30
+
31
+ def parse_opts(args)
32
+ @options = defaults
33
+ @options.merge!(Hash.transform_keys_to_symbols(Util.parse_config(MODULESYNC_CONF_FILE)))
34
+ @options[:command] = args[0] if commands_available.include?(args[0])
35
+ opt_parser = OptionParser.new do |opts|
36
+ opts.banner = "Usage: msync update [-m <commit message>] [-c <directory> ] [--noop] [-n <namespace>] [-b <branch>] | hook activate|deactivate [-c <directory> ] [-n <namespace>] [-b <branch>]"
37
+ opts.on('-m', '--message <msg>',
38
+ 'Commit message to apply to updated modules') do |msg|
39
+ @options[:message] = msg
40
+ end
41
+ opts.on('-n', '--namespace <url>',
42
+ 'Remote github namespace (user or organization) to clone from and push to. Defaults to puppetlabs') do |namespace|
43
+ @options[:namespace] = namespace
44
+ end
45
+ opts.on('-c', '--configs <directory>',
46
+ 'The local directory or remote repository to define the list of managed modules, the file templates, and the default values for template variables.') do |configs|
47
+ @options[:configs] = configs
48
+ end
49
+ opts.on('-b', '--branch <branch>',
50
+ 'Branch name to make the changes in. Defaults to "master"') do |branch|
51
+ @options[:branch] = branch
52
+ end
53
+ opts.on('--noop',
54
+ 'No-op mode') do |msg|
55
+ @options[:noop] = true
56
+ end
57
+ @options[:help] = opts.help
58
+ end.parse!
59
+
60
+ @options.fetch(:message) do
61
+ if @options[:command] == 'update' && ! @options[:noop]
62
+ fail("A commit message is required unless using noop.")
63
+ end
64
+ end
65
+
66
+ @options.fetch(:command) do
67
+ fail("A command is required.")
68
+ end
69
+
70
+ if @options[:command] == 'hook' &&
71
+ (! args.include?('activate') && ! args.include?('deactivate'))
72
+ fail("You must activate or deactivate the hook.")
73
+ end
74
+
75
+ end
76
+
77
+ def options
78
+ @options
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,11 @@
1
+ module ModuleSync
2
+ module Constants
3
+ MODULE_FILES_DIR = 'moduleroot/'
4
+ CONF_FILE = 'config_defaults.yml'
5
+ MODULE_CONF_FILE = '.sync.yml'
6
+ MODULESYNC_CONF_FILE = 'modulesync.yml'
7
+ PROJ_ROOT = './modules'
8
+ ENDPOINT = 'git@github.com'
9
+ HOOK_FILE = '.git/hooks/pre-push'
10
+ end
11
+ end
@@ -0,0 +1,81 @@
1
+ require 'git'
2
+
3
+ module ModuleSync
4
+ module Git
5
+ include Constants
6
+
7
+ def self.pull(org, name)
8
+ if ! Dir.exists?(PROJ_ROOT)
9
+ Dir.mkdir(PROJ_ROOT)
10
+ end
11
+
12
+ # Repo needs to be cloned in the cwd
13
+ if ! Dir.exists?("#{PROJ_ROOT}/#{name}") || ! Dir.exists?("#{PROJ_ROOT}/#{name}/.git")
14
+ puts "Cloning repository fresh"
15
+ remote = "#{ENDPOINT}:#{org}/#{name}.git"
16
+ local = "#{PROJ_ROOT}/#{name}"
17
+ repo = ::Git.clone(remote, local)
18
+
19
+ # Repo already cloned, check out master and override local changes
20
+ else
21
+ puts "Overriding any local changes to repositories in #{PROJ_ROOT}"
22
+ repo = ::Git.open("#{PROJ_ROOT}/#{name}")
23
+ repo.branch('master').checkout
24
+ repo.reset_hard
25
+ repo.pull
26
+ end
27
+ end
28
+
29
+ # Git add/rm, git commit, git push
30
+ def self.update(name, files, message, branch)
31
+ repo = ::Git.open("#{PROJ_ROOT}/#{name}")
32
+ repo.branch(branch).checkout
33
+ files.each do |file|
34
+ if repo.status.deleted.include?(file)
35
+ repo.remove(file)
36
+ else
37
+ repo.add(file)
38
+ end
39
+ end
40
+ begin
41
+ repo.commit(message)
42
+ #repo.push
43
+ rescue ::Git::GitExecuteError => git_error
44
+ if git_error.message.include? "nothing to commit, working directory clean"
45
+ puts "There were no files to update in #{name}. Not committing."
46
+ else
47
+ puts git_error
48
+ exit
49
+ end
50
+ end
51
+ end
52
+
53
+ # Needed because of a bug in the git gem that lists ignored files as
54
+ # untracked under some circumstances
55
+ # https://github.com/schacon/ruby-git/issues/130
56
+ def self.untracked_unignored_files(repo)
57
+ ignored = File.open("#{repo.dir.path}/.gitignore").read.split
58
+ repo.status.untracked.keep_if{|f,_| !ignored.any?{|i| f.match(/#{i}/)}}
59
+ end
60
+
61
+ def self.update_noop(name, branch)
62
+ puts "Using no-op. Files in #{name} may be changed but will not be committed."
63
+
64
+ repo = ::Git.open("#{PROJ_ROOT}/#{name}")
65
+ repo.branch(branch).checkout
66
+
67
+ puts "Files changed: "
68
+ repo.diff('HEAD', '--').each do |diff|
69
+ puts diff.patch
70
+ end
71
+
72
+ puts "Files added: "
73
+ untracked_unignored_files(repo).each do |file,_|
74
+ puts file
75
+ end
76
+
77
+ puts "\n\n"
78
+ puts '--------------------------------'
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,36 @@
1
+ module ModuleSync
2
+ module Hook
3
+ include Constants
4
+
5
+ def self.activate(args)
6
+ repo = args[:configs]
7
+ hook_args = ''
8
+ hook_args <<= " -n #{args[:namespace]}" if args[:namespace]
9
+ hook_args <<= " -b #{args[:branch]}" if args[:branch]
10
+ hook = <<EOF
11
+ #!/usr/bin/env bash
12
+
13
+ current_branch=\`git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,'\`
14
+ git_dir=\`git rev-parse --show-toplevel\`
15
+ message=\`git log -1 --format=%B\`
16
+ msync -m "\$message"#{hook_args}
17
+ EOF
18
+ File.open("#{repo}/#{HOOK_FILE}", 'w') do |file|
19
+ file.write(hook)
20
+ end
21
+ end
22
+
23
+ def self.deactivate(repo)
24
+ hook_path = "#{repo}/#{HOOK_FILE}"
25
+ File.delete(hook_path) if File.exists?(hook_path)
26
+ end
27
+
28
+ def self.hook(command, args)
29
+ if (command == 'activate')
30
+ activate(args)
31
+ else
32
+ deactivate(args[:configs])
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,41 @@
1
+ require 'erb'
2
+ require 'find'
3
+
4
+ module ModuleSync
5
+ module Renderer
6
+
7
+ class ForgeModuleFile
8
+ def initialize(configs= {})
9
+ @configs = configs
10
+ end
11
+ end
12
+
13
+ def self.build(from_erb_template)
14
+ erb_obj = ERB.new(File.read(from_erb_template), nil, '-')
15
+ erb_obj.filename = from_erb_template.chomp('.erb')
16
+ erb_obj.def_method(ForgeModuleFile, 'render()')
17
+ erb_obj
18
+ end
19
+
20
+ def self.remove(file)
21
+ if File.exists?(file)
22
+ File.delete(file)
23
+ end
24
+ end
25
+
26
+ def self.render(template, configs = {})
27
+ ForgeModuleFile.new(configs).render()
28
+ end
29
+
30
+ def self.sync(template, to_file)
31
+ path = to_file.rpartition('/').first
32
+ if(! path.empty?)
33
+ FileUtils.mkdir_p(path)
34
+ end
35
+ File.open(to_file, 'w') do |file|
36
+ file.write(template)
37
+ end
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ require 'yaml'
2
+
3
+ module ModuleSync
4
+ module Util
5
+
6
+ def self.parse_config(config_file)
7
+ if File.exist?(config_file)
8
+ YAML.load_file(config_file) || {}
9
+ else
10
+ {}
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ class Hash
17
+ #take keys of hash and transform those to a symbols
18
+ def self.transform_keys_to_symbols(value)
19
+ return value if not value.is_a?(Hash)
20
+ hash = value.inject({}){|memo,(k,v)| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); memo}
21
+ return hash
22
+ end
23
+ end
data/lib/modulesync.rb ADDED
@@ -0,0 +1,86 @@
1
+ require 'fileutils'
2
+ require 'modulesync/cli'
3
+ require 'modulesync/constants'
4
+ require 'modulesync/git'
5
+ require 'modulesync/hook'
6
+ require 'modulesync/renderer'
7
+ require 'modulesync/util'
8
+
9
+ module ModuleSync
10
+ include Constants
11
+
12
+ def self.local_file(config_path, file)
13
+ "#{config_path}/#{MODULE_FILES_DIR}/#{file}"
14
+ end
15
+
16
+ def self.module_file(puppet_module, file)
17
+ "#{PROJ_ROOT}/#{puppet_module}/#{file}"
18
+ end
19
+
20
+ def self.local_files(path)
21
+ if File.exists?(path)
22
+ local_files = Find.find(path).collect { |file| file if !File.directory?(file) }.compact
23
+ else
24
+ puts "#{path} does not exist. Check that you are working in your module configs directory or that you have passed in the correct directory with -c."
25
+ exit
26
+ end
27
+ end
28
+
29
+ def self.module_files(local_files, path)
30
+ local_files.map { |file| file.sub(/#{path}/, '') }
31
+ end
32
+
33
+ def self.managed_modules(path)
34
+ managed_modules = Util.parse_config(path)
35
+ if managed_modules.empty?
36
+ puts "No modules found at #{path}. Check that you specified the right configs directory containing managed_modules.yml."
37
+ exit
38
+ end
39
+ managed_modules
40
+ end
41
+
42
+ def self.run(args)
43
+ cli = CLI.new
44
+ cli.parse_opts(args)
45
+ options = cli.options
46
+ if options[:command] == 'update'
47
+ defaults = Util.parse_config("#{options[:configs]}/#{CONF_FILE}")
48
+
49
+ path = "#{options[:configs]}/#{MODULE_FILES_DIR}"
50
+ local_files = self.local_files(path)
51
+ module_files = self.module_files(local_files, path)
52
+
53
+ managed_modules = self.managed_modules("#{options[:configs]}/managed_modules.yml")
54
+
55
+ managed_modules.each do |puppet_module|
56
+ puts "Syncing #{puppet_module}"
57
+ Git.pull(options[:namespace], puppet_module)
58
+ module_configs = Util.parse_config("#{PROJ_ROOT}/#{puppet_module}/#{MODULE_CONF_FILE}")
59
+ files_to_manage = module_files | defaults.keys | module_configs.keys
60
+ files_to_delete = []
61
+ files_to_manage.each do |file|
62
+ file_configs = (defaults[file] || {}).merge(module_configs[file] || {})
63
+ if file_configs['unmanaged']
64
+ puts "Not managing #{file} in #{puppet_module}"
65
+ files_to_delete << file
66
+ elsif file_configs['delete']
67
+ Renderer.remove(module_file(puppet_module, file))
68
+ else
69
+ erb = Renderer.build(local_file(options[:configs], file))
70
+ template = Renderer.render(erb, file_configs)
71
+ Renderer.sync(template, "#{PROJ_ROOT}/#{puppet_module}/#{file}")
72
+ end
73
+ end
74
+ files_to_manage -= files_to_delete
75
+ if options[:noop]
76
+ Git.update_noop(puppet_module, options[:branch])
77
+ else
78
+ Git.update(puppet_module, files_to_manage, options[:message], options[:branch])
79
+ end
80
+ end
81
+ elsif options[:command] == 'hook'
82
+ Hook.hook(args[1], options)
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'modulesync'
7
+ spec.version = '0.0.1'
8
+ spec.authors = ['Colleen Murphy']
9
+ spec.email = ['colleen@puppetlabs.com']
10
+ spec.summary = %q{Puppet Module Synchronizer}
11
+ spec.description = %q{Utility to synchronize common files across puppet modules in Github.}
12
+ spec.homepage = "http://github.com/puppetlabs/modulesync"
13
+ spec.license = "Apache 2"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.6"
21
+
22
+ spec.add_runtime_dependency 'git', '~>1.2'
23
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: modulesync
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Colleen Murphy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-02 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: git
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ description: Utility to synchronize common files across puppet modules in Github.
42
+ email:
43
+ - colleen@puppetlabs.com
44
+ executables:
45
+ - msync
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - .gitignore
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - LICENSE
53
+ - README.md
54
+ - bin/msync
55
+ - lib/modulesync.rb
56
+ - lib/modulesync/cli.rb
57
+ - lib/modulesync/constants.rb
58
+ - lib/modulesync/git.rb
59
+ - lib/modulesync/hook.rb
60
+ - lib/modulesync/renderer.rb
61
+ - lib/modulesync/util.rb
62
+ - modulesync.gemspec
63
+ homepage: http://github.com/puppetlabs/modulesync
64
+ licenses:
65
+ - Apache 2
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.2.2
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Puppet Module Synchronizer
87
+ test_files: []
88
+ has_rdoc: