modulesync 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16cd854b2ba5a64f73b1051081fbf1e3bdbe39bbec2b7dacf5de3a3f37750625
4
- data.tar.gz: d45c398dd5e7fc20d4bbf257ca0303bda0faa91ea49d3b6804d34fdbb25e1175
3
+ metadata.gz: 139a0b0b011d17ff31b014560eb02ce6a57e62f2e45ffaa06c9acf778240b047
4
+ data.tar.gz: f1696a42bcf9cf44719ea8f7c5f5580481672e9c3dd920463f77f2f72d54a82a
5
5
  SHA512:
6
- metadata.gz: 38ae3613c9b28a0d679445350dcf6d625ad0db7156db8e26df7b4a4703a79713b471ce786d20d879a4bcdf8cd23830ac8277f259435f6fb191eede8a5a49ac9f
7
- data.tar.gz: 62cacbdc9b002371957bc732727774c79d3b5783280469e3a2a34379265b784a8b6c0a6bccf1ce47ceb4bccea27cdb0273933b86381a37d57fd39e011b382d49
6
+ metadata.gz: 22bf21a62e3c6e3c8df65bed7b1356af3dc656ba85ae885338b0f35b501c1217c5159918d2c21fcbe3c92c52d14ab2f561b876004eabec99ecaa81521c875c88
7
+ data.tar.gz: 751fdcd7d6ee62611f90659e21eb94a103ac6473c98b6907342441675232e1c946dc69ed925dff5e1f708dd4e5f8dca68e039b38600d7c73c9f919dc837a9aee
@@ -7,6 +7,7 @@ AllCops:
7
7
  - 'tmp/**/*'
8
8
  - 'pkg/**/*'
9
9
  - 'lib/monkey_patches.rb'
10
+ - 'spec/**/*'
10
11
 
11
12
  Style/HashSyntax:
12
13
  Enabled: false
@@ -6,10 +6,13 @@ dist: trusty
6
6
  script: 'bundle exec rake test'
7
7
  rvm:
8
8
  - 2.0
9
- - 2.1.9
10
- - 2.2.6
11
- - 2.3.3
12
- - 2.4.0
9
+ - 2.1
10
+ - 2.2
11
+ - 2.3
12
+ - 2.4
13
+ - 2.5
14
+ - 2.6
15
+ - 2.7
13
16
  notifications:
14
17
  email: false
15
18
  deploy:
@@ -18,7 +21,7 @@ deploy:
18
21
  secure: "Tbf1EbLEobIIox+fftJZADZsfQQ6kl0urcMNetK7NJzFo/negD/WyJIUj3kro/B7buyYADEjTui/JR4o8EPbugfM3ie5vYOd5k3AesSzbdr4BSwGe/cGbGOB7/PZuGfFLkb94/FiCU2mIwibkbh1rHWGlBoPj7ntL0+5ZtdvsM4="
19
22
  gem: modulesync
20
23
  on:
21
- rvm: 2.4.0
24
+ rvm: 2.7
22
25
  tags: true
23
26
  all_branches: true
24
27
  repo: voxpupuli/modulesync
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 2020-05-01 - 1.1.0
4
+
5
+ This release provides metadata in the ERB template scope which makes it easy to read files from inside the module. A possible application is reading metadata.json and generating CI configs based on that.
6
+
7
+ * Add metadata to ERB template scope - [#168](https://github.com/voxpupuli/modulesync/pull/168)
8
+ * Skip issuing a PR if one already exists for -b option - [#171](https://github.com/voxpupuli/modulesync/pull/171)
9
+ * Correct the type on the pr-labels option to prevent a deprecation warning - [#173](https://github.com/voxpupuli/modulesync/pull/173)
10
+
3
11
  ## 2019-09-19 - 1.0.0
4
12
 
5
13
  This is the first stable release! 🎉
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source ENV['GEM_SOURCE'] || 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  gem 'cucumber', '< 3.0' if RUBY_VERSION < '2.1'
6
- gem 'octokit', '~> 4.0'
6
+ gem 'octokit', '~> 4.9'
data/README.md CHANGED
@@ -389,6 +389,23 @@ As mentioned, files in the moduleroot directory must be ERB templates (they must
389
389
  <%= @configs[:puppet_module] %>
390
390
  ```
391
391
 
392
+ Alternatively some meta data is passed to the template. This will allow you to add custom Ruby extensions inside the
393
+ template, reading other files from the module, to make the template system more adaptive.
394
+
395
+ ```erb
396
+ module: <%= @metadata[:module_name] %>
397
+ target: <%= @metadata[:target_file] %>
398
+ workdir: <%= @metadata[:workdir] %>
399
+ ```
400
+
401
+ Will result in something like:
402
+
403
+ ```
404
+ module: puppet-test
405
+ target: modules/github-org/puppet-test/test
406
+ workdir: modules/github-org/puppet-test
407
+ ```
408
+
392
409
  The Templates
393
410
  -------------
394
411
 
data/Rakefile CHANGED
@@ -19,3 +19,4 @@ Cucumber::Rake::Task.new do |t|
19
19
  end
20
20
 
21
21
  task :test => %i[clean spec cucumber rubocop]
22
+ task :default => %i[test]
@@ -922,3 +922,36 @@ Feature: update
922
922
  When I run `msync update -m "Update Gemfile"`
923
923
  Then the exit status should be 0
924
924
  Then the output should contain "Using repository's default branch: develop"
925
+
926
+ Scenario: Adding a new file from a template using meta data
927
+ And a file named "config_defaults.yml" with:
928
+ """
929
+ ---
930
+ """
931
+ Given a file named "managed_modules.yml" with:
932
+ """
933
+ ---
934
+ - puppet-test
935
+ """
936
+ And a file named "modulesync.yml" with:
937
+ """
938
+ ---
939
+ namespace: maestrodev
940
+ git_base: https://github.com/
941
+ """
942
+ And a directory named "moduleroot"
943
+ And a file named "moduleroot/test.erb" with:
944
+ """
945
+ module: <%= @metadata[:module_name] %>
946
+ target: <%= @metadata[:target_file] %>
947
+ workdir: <%= @metadata[:workdir] %>
948
+ """
949
+ When I run `msync update --noop`
950
+ Then the exit status should be 0
951
+ Given I run `cat modules/maestrodev/puppet-test/test`
952
+ Then the output should contain:
953
+ """
954
+ module: puppet-test
955
+ target: modules/maestrodev/puppet-test/test
956
+ workdir: modules/maestrodev/puppet-test
957
+ """
@@ -16,7 +16,7 @@ Octokit.configure do |c|
16
16
  c.api_endpoint = ENV.fetch('GITHUB_BASE_URL', 'https://api.github.com')
17
17
  end
18
18
 
19
- module ModuleSync
19
+ module ModuleSync # rubocop:disable Metrics/ModuleLength
20
20
  include Constants
21
21
 
22
22
  def self.config_defaults
@@ -32,8 +32,8 @@ module ModuleSync
32
32
  File.join(config_path, MODULE_FILES_DIR, file)
33
33
  end
34
34
 
35
- def self.module_file(project_root, namespace, puppet_module, file)
36
- File.join(project_root, namespace, puppet_module, file)
35
+ def self.module_file(project_root, namespace, puppet_module, *parts)
36
+ File.join(project_root, namespace, puppet_module, *parts)
37
37
  end
38
38
 
39
39
  # List all template files.
@@ -46,7 +46,7 @@ module ModuleSync
46
46
  .collect { |p| p.chomp('.erb') }
47
47
  .to_a
48
48
  else
49
- puts "#{local_template_dir} does not exist." \
49
+ $stdout.puts "#{local_template_dir} does not exist." \
50
50
  ' Check that you are working in your module configs directory or' \
51
51
  ' that you have passed in the correct directory with -c.'
52
52
  exit
@@ -60,7 +60,7 @@ module ModuleSync
60
60
  def self.managed_modules(config_file, filter, negative_filter)
61
61
  managed_modules = Util.parse_config(config_file)
62
62
  if managed_modules.empty?
63
- puts "No modules found in #{config_file}." \
63
+ $stdout.puts "No modules found in #{config_file}." \
64
64
  ' Check that you specified the right :configs directory and :managed_modules_conf file.'
65
65
  exit
66
66
  end
@@ -89,27 +89,29 @@ module ModuleSync
89
89
  namespace = settings.additional_settings[:namespace]
90
90
  module_name = settings.additional_settings[:puppet_module]
91
91
  configs = settings.build_file_configs(filename)
92
+ target_file = module_file(options[:project_root], namespace, module_name, filename)
92
93
  if configs['delete']
93
- Renderer.remove(module_file(options[:project_root], namespace, module_name, filename))
94
+ Renderer.remove(target_file)
94
95
  else
95
96
  templatename = local_file(options[:configs], filename)
96
97
  begin
97
98
  erb = Renderer.build(templatename)
98
- template = Renderer.render(erb, configs)
99
- Renderer.sync(template, module_file(options[:project_root], namespace, module_name, filename))
99
+ # Meta data passed to the template as @metadata[:name]
100
+ metadata = {
101
+ :module_name => module_name,
102
+ :workdir => module_file(options[:project_root], namespace, module_name),
103
+ :target_file => target_file,
104
+ }
105
+ template = Renderer.render(erb, configs, metadata)
106
+ Renderer.sync(template, target_file)
100
107
  rescue # rubocop:disable Lint/RescueWithoutErrorClass
101
- STDERR.puts "Error while rendering #{filename}"
108
+ $stderr.puts "Error while rendering #{filename}"
102
109
  raise
103
110
  end
104
111
  end
105
112
  end
106
113
 
107
114
  def self.manage_module(puppet_module, module_files, module_options, defaults, options)
108
- if options[:pr] && !GITHUB_TOKEN
109
- STDERR.puts 'Environment variable GITHUB_TOKEN must be set to use --pr!'
110
- raise unless options[:skip_broken]
111
- end
112
-
113
115
  namespace, module_name = module_name(puppet_module, options[:namespace])
114
116
  git_repo = File.join(namespace, module_name)
115
117
  unless options[:offline]
@@ -125,7 +127,7 @@ module ModuleSync
125
127
  :git_base => options[:git_base],
126
128
  :namespace => namespace)
127
129
  settings.unmanaged_files(module_files).each do |filename|
128
- puts "Not managing #{filename} in #{module_name}"
130
+ $stdout.puts "Not managing #{filename} in #{module_name}"
129
131
  end
130
132
 
131
133
  files_to_manage = settings.managed_files(module_files)
@@ -138,24 +140,39 @@ module ModuleSync
138
140
  pushed = Git.update(git_repo, files_to_manage, options)
139
141
  return nil unless pushed && options[:pr]
140
142
 
141
- # We only do GitHub PR work if the GITHUB_TOKEN variable is set in the environment.
142
- repo_path = File.join(namespace, module_name)
143
- puts "Submitting PR '#{options[:pr_title]}' on GitHub to #{repo_path} - merges #{options[:branch]} into master"
144
- github = Octokit::Client.new(:access_token => GITHUB_TOKEN)
145
- pr = github.create_pull_request(repo_path, 'master', options[:branch], options[:pr_title], options[:message])
146
- puts "PR created at #{pr['html_url']}"
143
+ manage_pr(namespace, module_name, options)
144
+ end
145
+ end
146
+
147
+ def self.manage_pr(namespace, module_name, options)
148
+ if options[:pr] && GITHUB_TOKEN.empty?
149
+ $stderr.puts 'Environment variable GITHUB_TOKEN must be set to use --pr!'
150
+ raise unless options[:skip_broken]
151
+ end
147
152
 
148
- # PR labels can either be a list in the YAML file or they can pass in a comma
149
- # separated list via the command line argument.
150
- pr_labels = Util.parse_list(options[:pr_labels])
153
+ # We only do GitHub PR work if the GITHUB_TOKEN variable is set in the environment.
154
+ repo_path = File.join(namespace, module_name)
155
+ github = Octokit::Client.new(:access_token => GITHUB_TOKEN)
151
156
 
152
- # We only assign labels to the PR if we've discovered a list > 1. The labels MUST
153
- # already exist. We DO NOT create missing labels.
154
- unless pr_labels.empty?
155
- puts "Attaching the following labels to PR #{pr['number']}: #{pr_labels.join(', ')}"
156
- github.add_labels_to_an_issue(repo_path, pr['number'], pr_labels)
157
- end
157
+ # Skip creating the PR if it exists already.
158
+ head = "#{namespace}:#{options[:branch]}"
159
+ pull_requests = github.pull_requests(repo_path, :state => 'open', :base => 'master', :head => head)
160
+ if pull_requests.empty?
161
+ pr = github.create_pull_request(repo_path, 'master', options[:branch], options[:pr_title], options[:message])
162
+ $stdout.puts "Submitted PR '#{options[:pr_title]}' to #{repo_path} - merges #{options[:branch]} into master"
163
+ else
164
+ $stdout.puts "Skipped! #{pull_requests.length} PRs found for branch #{options[:branch]}"
158
165
  end
166
+
167
+ # PR labels can either be a list in the YAML file or they can pass in a comma
168
+ # separated list via the command line argument.
169
+ pr_labels = Util.parse_list(options[:pr_labels])
170
+
171
+ # We only assign labels to the PR if we've discovered a list > 1. The labels MUST
172
+ # already exist. We DO NOT create missing labels.
173
+ return if pr_labels.empty?
174
+ $stdout.puts "Attaching the following labels to PR #{pr['number']}: #{pr_labels.join(', ')}"
175
+ github.add_labels_to_an_issue(repo_path, pr['number'], pr_labels)
159
176
  end
160
177
 
161
178
  def self.update(options)
@@ -176,10 +193,10 @@ module ModuleSync
176
193
  begin
177
194
  manage_module(puppet_module, module_files, module_options, defaults, options)
178
195
  rescue # rubocop:disable Lint/RescueWithoutErrorClass
179
- STDERR.puts "Error while updating #{puppet_module}"
196
+ $stderr.puts "Error while updating #{puppet_module}"
180
197
  raise unless options[:skip_broken]
181
198
  errors = true
182
- puts "Skipping #{puppet_module} as update process failed"
199
+ $stdout.puts "Skipping #{puppet_module} as update process failed"
183
200
  end
184
201
  end
185
202
  exit 1 if errors && options[:fail_on_warnings]
@@ -96,6 +96,7 @@ module ModuleSync
96
96
  :desc => 'Title of GitHub PR',
97
97
  :default => CLI.defaults[:pr_title] || 'Update to module template files'
98
98
  option :pr_labels,
99
+ :type => :array,
99
100
  :desc => 'Labels to add to the GitHub PR',
100
101
  :default => CLI.defaults[:pr_labels] || []
101
102
  option :offline,
@@ -4,8 +4,9 @@ require 'find'
4
4
  module ModuleSync
5
5
  module Renderer
6
6
  class ForgeModuleFile
7
- def initialize(configs = {})
7
+ def initialize(configs = {}, metadata = {})
8
8
  @configs = configs
9
+ @metadata = metadata
9
10
  end
10
11
  end
11
12
 
@@ -26,8 +27,8 @@ module ModuleSync
26
27
  File.delete(file) if File.exist?(file)
27
28
  end
28
29
 
29
- def self.render(_template, configs = {})
30
- ForgeModuleFile.new(configs).render
30
+ def self.render(_template, configs = {}, metadata = {})
31
+ ForgeModuleFile.new(configs, metadata).render
31
32
  end
32
33
 
33
34
  def self.sync(template, target_name)
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = 'modulesync'
6
- spec.version = '1.0.0'
6
+ spec.version = '1.1.0'
7
7
  spec.authors = ['Vox Pupuli']
8
8
  spec.email = ['voxpupuli@groups.io']
9
9
  spec.summary = 'Puppet Module Synchronizer'
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ['lib']
19
19
 
20
- spec.add_development_dependency 'aruba'
20
+ spec.add_development_dependency 'aruba', '~> 0.14'
21
21
  spec.add_development_dependency 'bundler'
22
22
  spec.add_development_dependency 'rake'
23
23
  spec.add_development_dependency 'rspec'
@@ -11,4 +11,59 @@ describe ModuleSync do
11
11
  ModuleSync.update(options)
12
12
  end
13
13
  end
14
+
15
+ context '::manage_pr' do
16
+ before(:each) do
17
+ stub_const('GITHUB_TOKEN', 'test')
18
+ @git_repo = 'test/modulesync'
19
+ @namespace, @repo_name = @git_repo.split('/')
20
+ @options = {
21
+ :pr => true,
22
+ :pr_title => 'Test PR is submitted',
23
+ :branch => 'test',
24
+ :message => 'Hello world',
25
+ :pr_auto_merge => false,
26
+ }
27
+
28
+ @client = double()
29
+ end
30
+
31
+ it 'rasies an error when GITHUB_TOKEN not set for PRs' do
32
+ stub_const('GITHUB_TOKEN', '')
33
+ options = {:pr => true, :skip_broken => false}
34
+
35
+ expect { ModuleSync.manage_pr(@namespace, @repo_name, options) }.to raise_error(RuntimeError).and output(/GITHUB_TOKEN/).to_stderr
36
+ end
37
+
38
+ it 'submits PR when --pr is set' do
39
+ allow(Octokit::Client).to receive(:new).and_return(@client)
40
+ allow(@client).to receive(:pull_requests).with(@git_repo, :state => 'open', :base => 'master', :head => "#{@namespace}:#{@options[:branch]}").and_return([])
41
+ expect(@client).to receive(:create_pull_request).with(@git_repo, 'master', @options[:branch], @options[:pr_title], @options[:message]).and_return({"html_url" => "http://example.com/pulls/22"})
42
+ expect { ModuleSync.manage_pr(@namespace, @repo_name, @options) }.to output(/Submitted PR/).to_stdout
43
+ end
44
+
45
+ it 'skips submitting PR if one has already been issued' do
46
+ allow(Octokit::Client).to receive(:new).and_return(@client)
47
+
48
+ pr = {
49
+ "title" => "Test title",
50
+ "html_url" => "https://example.com/pulls/44",
51
+ "number" => "44"
52
+ }
53
+
54
+ expect(@client).to receive(:pull_requests).with(@git_repo, :state => 'open', :base => 'master', :head => "#{@namespace}:#{@options[:branch]}").and_return([pr])
55
+ expect { ModuleSync.manage_pr(@namespace, @repo_name, @options) }.to output(/Skipped! 1 PRs found for branch test/).to_stdout
56
+ end
57
+
58
+ it 'adds labels to PR when --pr-labels is set' do
59
+ @options[:pr_labels] = "HELLO,WORLD"
60
+
61
+ allow(Octokit::Client).to receive(:new).and_return(@client)
62
+ allow(@client).to receive(:create_pull_request).and_return({"html_url" => "http://example.com/pulls/22", "number" => "44"})
63
+ allow(@client).to receive(:pull_requests).with(@git_repo, :state => 'open', :base => 'master', :head => "#{@namespace}:#{@options[:branch]}").and_return([])
64
+
65
+ expect(@client).to receive(:add_labels_to_an_issue).with(@git_repo, "44", ["HELLO", "WORLD"])
66
+ expect { ModuleSync.manage_pr(@namespace, @repo_name, @options) }.to output(/Attaching the following labels to PR 44: HELLO, WORLD/).to_stdout
67
+ end
68
+ end
14
69
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: modulesync
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vox Pupuli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-19 00:00:00.000000000 Z
11
+ date: 2020-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aruba
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '0.14'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '0.14'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -193,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
195
  requirements: []
196
- rubygems_version: 3.0.6
196
+ rubygems_version: 3.1.2
197
197
  signing_key:
198
198
  specification_version: 4
199
199
  summary: Puppet Module Synchronizer