modulesync 2.0.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,57 @@
1
+ require 'modulesync'
2
+ require 'modulesync/repository'
3
+ require 'modulesync/util'
4
+
5
+ module ModuleSync
6
+ # Provide methods to retrieve source code attributes
7
+ class SourceCode
8
+ attr_reader :given_name
9
+ attr_reader :options
10
+
11
+ def initialize(given_name, options)
12
+ @options = Util.symbolize_keys(options || {})
13
+
14
+ @given_name = given_name
15
+
16
+ return unless given_name.include?('/')
17
+
18
+ @repository_name = given_name.split('/').last
19
+ @repository_namespace = given_name.split('/')[0...-1].join('/')
20
+ end
21
+
22
+ def repository
23
+ @repository ||= Repository.new directory: working_directory, remote: repository_remote
24
+ end
25
+
26
+ def repository_name
27
+ @repository_name ||= given_name
28
+ end
29
+
30
+ def repository_namespace
31
+ @repository_namespace ||= @options[:namespace] || ModuleSync.options[:namespace]
32
+ end
33
+
34
+ def repository_path
35
+ @repository_path ||= "#{repository_namespace}/#{repository_name}"
36
+ end
37
+
38
+ def repository_remote
39
+ @repository_remote ||= @options[:remote] || _repository_remote
40
+ end
41
+
42
+ def working_directory
43
+ @working_directory ||= File.join(ModuleSync.options[:project_root], repository_path)
44
+ end
45
+
46
+ def path(*parts)
47
+ File.join(working_directory, *parts)
48
+ end
49
+
50
+ private
51
+
52
+ def _repository_remote
53
+ git_base = ModuleSync.options[:git_base]
54
+ git_base.start_with?('file://') ? "#{git_base}#{repository_path}" : "#{git_base}#{repository_path}.git"
55
+ end
56
+ end
57
+ end
@@ -1,55 +1,16 @@
1
1
  module Git
2
- class Diff
3
- # Monkey patch process_full_diff until https://github.com/schacon/ruby-git/issues/326 is resolved
4
- def process_full_diff
5
- defaults = {
6
- :mode => '',
7
- :src => '',
8
- :dst => '',
9
- :type => 'modified'
10
- }
11
- final = {}
12
- current_file = nil
13
- full_diff_utf8_encoded = @full_diff.encode("UTF-8", "binary", {
14
- :invalid => :replace,
15
- :undef => :replace
16
- })
17
- full_diff_utf8_encoded.split("\n").each do |line|
18
- if m = /^diff --git a\/(.*?) b\/(.*?)/.match(line)
19
- current_file = m[1]
20
- final[current_file] = defaults.merge({:patch => line, :path => current_file})
21
- elsif !current_file.nil?
22
- if m = /^index (.......)\.\.(.......)( ......)*/.match(line)
23
- final[current_file][:src] = m[1]
24
- final[current_file][:dst] = m[2]
25
- final[current_file][:mode] = m[3].strip if m[3]
26
- end
27
- if m = /^([[:alpha:]]*?) file mode (......)/.match(line)
28
- final[current_file][:type] = m[1]
29
- final[current_file][:mode] = m[2]
30
- end
31
- if m = /^Binary files /.match(line)
32
- final[current_file][:binary] = true
33
- end
34
- final[current_file][:patch] << "\n" + line
35
- end
36
- end
37
- final.map { |e| [e[0], DiffFile.new(@base, e[1])] }
2
+ module LibMonkeyPatch
3
+ # Monkey patch set_custom_git_env_variables due to our ::Git::GitExecuteError handling.
4
+ #
5
+ # We rescue on the GitExecuteError and proceed differently based on the output of git.
6
+ # This way makes code language-dependent, so here we ensure that Git gem throw git commands with the "C" language
7
+ def set_custom_git_env_variables
8
+ super
9
+ ENV['LANG'] = 'C.UTF-8'
38
10
  end
39
11
  end
40
12
 
41
13
  class Lib
42
- # Monkey patch ls_files until https://github.com/ruby-git/ruby-git/pull/320 is resolved
43
- def ls_files(location=nil)
44
- location ||= '.'
45
- hsh = {}
46
- command_lines('ls-files', ['--stage', location]).each do |line|
47
- (info, file) = line.split("\t")
48
- (mode, sha, stage) = info.split
49
- file = eval(file) if file =~ /^\".*\"$/ # This takes care of quoted strings returned from git
50
- hsh[file] = {:path => file, :mode_index => mode, :sha_index => sha, :stage => stage}
51
- end
52
- hsh
53
- end
14
+ prepend LibMonkeyPatch
54
15
  end
55
16
  end
data/modulesync.gemspec CHANGED
@@ -3,12 +3,12 @@ $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 = '2.0.1'
6
+ spec.version = '2.2.0'
7
7
  spec.authors = ['Vox Pupuli']
8
8
  spec.email = ['voxpupuli@groups.io']
9
9
  spec.summary = 'Puppet Module Synchronizer'
10
10
  spec.description = 'Utility to synchronize common files across puppet modules in Github.'
11
- spec.homepage = 'http://github.com/voxpupuli/modulesync'
11
+ spec.homepage = 'https://github.com/voxpupuli/modulesync'
12
12
  spec.license = 'Apache-2.0'
13
13
  spec.required_ruby_version = '>= 2.5.0'
14
14
 
@@ -17,13 +17,14 @@ 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', '~> 0.14'
20
+ spec.add_development_dependency 'aruba', '>= 0.14', '< 2'
21
21
  spec.add_development_dependency 'bundler'
22
22
  spec.add_development_dependency 'rake'
23
23
  spec.add_development_dependency 'rspec'
24
24
  spec.add_development_dependency 'rubocop', '~> 0.50.0'
25
+ spec.add_development_dependency 'cucumber'
25
26
 
26
- spec.add_runtime_dependency 'git', '~>1.3'
27
+ spec.add_runtime_dependency 'git', '~>1.7'
27
28
  spec.add_runtime_dependency 'gitlab', '~>4.0'
28
29
  spec.add_runtime_dependency 'octokit', '~>4.0'
29
30
  spec.add_runtime_dependency 'puppet-blacksmith', '>= 3.0', '< 7'
@@ -0,0 +1,14 @@
1
+ module ModuleSync
2
+ # Faker is a top-level module to keep global faker config
3
+ module Faker
4
+ def self.working_directory=(path)
5
+ @working_directory = path
6
+ end
7
+
8
+ def self.working_directory
9
+ raise 'Working directory must be set' if @working_directory.nil?
10
+ FileUtils.mkdir_p @working_directory
11
+ @working_directory
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,146 @@
1
+ require 'open3'
2
+
3
+ require_relative '../faker'
4
+
5
+ module ModuleSync
6
+ # Fake a remote git repository that holds a puppet module
7
+ #
8
+ # This module allows to fake a remote repositiory using:
9
+ # - a bare repo
10
+ # - a temporary cloned repo to operate on the remote before exposing to modulesync
11
+ #
12
+ # Note: This module needs to have working_directory sets before using it
13
+ module Faker
14
+ class PuppetModuleRemoteRepo
15
+ class CommandExecutionError < StandardError; end
16
+
17
+ attr_reader :name, :namespace
18
+
19
+ def initialize(name, namespace)
20
+ @name = name
21
+ @namespace = namespace
22
+ end
23
+
24
+ def populate
25
+ FileUtils.chdir(Faker.working_directory) do
26
+ run %W[git init --bare #{bare_repo_dir}]
27
+ run %W[git clone #{bare_repo_dir} #{tmp_repo_dir}]
28
+
29
+ module_short_name = name.split('-').last
30
+
31
+ FileUtils.chdir(tmp_repo_dir) do
32
+ metadata = {
33
+ name: "modulesync-#{module_short_name}",
34
+ version: '0.4.2',
35
+ author: 'ModuleSync team',
36
+ }
37
+
38
+ File.write 'metadata.json', metadata.to_json
39
+ run %w[git add metadata.json]
40
+ run %w[git commit --message] << 'Initial commit'
41
+ run %w[git push]
42
+ end
43
+ end
44
+ end
45
+
46
+ def read_only=(value)
47
+ mode = value ? '0444' : '0644'
48
+ FileUtils.chdir(bare_repo_dir) do
49
+ run %W[git config core.sharedRepository #{mode}]
50
+ end
51
+ end
52
+
53
+ def default_branch
54
+ FileUtils.chdir(bare_repo_dir) do
55
+ stdout = run %w[git symbolic-ref --short HEAD]
56
+ return stdout.chomp
57
+ end
58
+ end
59
+
60
+ def default_branch=(value)
61
+ FileUtils.chdir(bare_repo_dir) do
62
+ run %W[git branch -M #{default_branch} #{value}]
63
+ run %W[git symbolic-ref HEAD refs/heads/#{value}]
64
+ end
65
+ end
66
+
67
+ def read_file(filename, branch = nil)
68
+ branch ||= default_branch
69
+ FileUtils.chdir(bare_repo_dir) do
70
+ return run %W[git show #{branch}:#{filename}]
71
+ rescue CommandExecutionError
72
+ return nil
73
+ end
74
+ end
75
+
76
+ def add_file(filename, content, branch = nil)
77
+ branch ||= default_branch
78
+ FileUtils.chdir(tmp_repo_dir) do
79
+ run %W[git checkout #{branch}]
80
+ File.write filename, content
81
+ run %W[git add #{filename}]
82
+ run %w[git commit --message] << "Add file: '#{filename}'"
83
+ run %w[git push]
84
+ end
85
+ end
86
+
87
+ def commit_count_between(commit1, commit2)
88
+ FileUtils.chdir(bare_repo_dir) do
89
+ stdout = run %W[git rev-list --count #{commit1}..#{commit2}]
90
+ return Integer(stdout)
91
+ end
92
+ end
93
+
94
+ def commit_count_by(author, commit = nil)
95
+ FileUtils.chdir(bare_repo_dir) do
96
+ commit ||= '--all'
97
+ stdout = run %W[git rev-list #{commit} --author #{author} --count]
98
+ return Integer(stdout)
99
+ end
100
+ end
101
+
102
+ def tags
103
+ FileUtils.chdir(bare_repo_dir) do
104
+ return run %w{git tag --list}
105
+ end
106
+ end
107
+
108
+ def remote_url
109
+ "file://#{bare_repo_dir}"
110
+ end
111
+
112
+ def self.git_base
113
+ "file://#{Faker.working_directory}/bare/"
114
+ end
115
+
116
+ private
117
+
118
+ def tmp_repo_dir
119
+ File.join Faker.working_directory, 'tmp', namespace, name
120
+ end
121
+
122
+ def bare_repo_dir
123
+ File.join Faker.working_directory, 'bare', namespace, "#{name}.git"
124
+ end
125
+
126
+ GIT_ENV = {
127
+ 'GIT_AUTHOR_NAME' => 'Faker',
128
+ 'GIT_AUTHOR_EMAIL' => 'faker@example.com',
129
+ 'GIT_COMMITTER_NAME' => 'Faker',
130
+ 'GIT_COMMITTER_EMAIL' => 'faker@example.com',
131
+ }.freeze
132
+
133
+ def run(command)
134
+ stdout, stderr, status = Open3.capture3(GIT_ENV, *command)
135
+ return stdout if status.success?
136
+
137
+ warn "Command '#{command}' failed: #{status}"
138
+ warn ' STDOUT:'
139
+ warn stdout
140
+ warn ' STDERR:'
141
+ warn stderr
142
+ raise CommandExecutionError, "Command '#{command}' failed: #{status}"
143
+ end
144
+ end
145
+ end
146
+ end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,25 @@
1
+ begin
2
+ require 'simplecov'
3
+ require 'simplecov-console'
4
+ require 'codecov'
5
+ rescue LoadError
6
+ else
7
+ SimpleCov.start do
8
+ track_files 'lib/**/*.rb'
9
+
10
+ add_filter '/spec'
11
+
12
+ enable_coverage :branch
13
+
14
+ # do not track vendored files
15
+ add_filter '/vendor'
16
+ add_filter '/.vendor'
17
+ end
18
+
19
+ SimpleCov.formatters = [
20
+ SimpleCov::Formatter::Console,
21
+ SimpleCov::Formatter::Codecov,
22
+ ]
23
+ end
24
+
1
25
  require 'modulesync'
@@ -5,7 +5,7 @@ describe ModuleSync do
5
5
  it 'loads the managed modules from the specified :managed_modules_conf' do
6
6
  allow(ModuleSync).to receive(:find_template_files).and_return([])
7
7
  allow(ModuleSync::Util).to receive(:parse_config).with('./config_defaults.yml').and_return({})
8
- expect(ModuleSync).to receive(:managed_modules).with('./test_file.yml', nil, nil).and_return([])
8
+ expect(ModuleSync).to receive(:managed_modules).with(no_args).and_return([])
9
9
 
10
10
  options = { managed_modules_conf: 'test_file.yml' }
11
11
  ModuleSync.update(options)
@@ -14,8 +14,12 @@ describe ModuleSync do
14
14
 
15
15
  context '::pr' do
16
16
  describe "Raise Error" do
17
+ let(:puppet_module) do
18
+ ModuleSync::PuppetModule.new 'puppet-test', remote: 'dummy'
19
+ end
20
+
17
21
  it 'raises an error when neither GITHUB_TOKEN nor GITLAB_TOKEN are set for PRs' do
18
- expect { ModuleSync.pr({}) }.to raise_error(RuntimeError).and output(/No GitHub or GitLab token specified for --pr/).to_stderr
22
+ expect { ModuleSync.pr(puppet_module) }.to raise_error(RuntimeError).and output(/No GitHub or GitLab token specified for --pr/).to_stderr
19
23
  end
20
24
  end
21
25
  end
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: modulesync
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.2.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: 2020-10-06 00:00:00.000000000 Z
11
+ date: 2021-07-24 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
19
  version: '0.14'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2'
20
23
  type: :development
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '0.14'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: bundler
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +86,34 @@ dependencies:
80
86
  - - "~>"
81
87
  - !ruby/object:Gem::Version
82
88
  version: 0.50.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: cucumber
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
83
103
  - !ruby/object:Gem::Dependency
84
104
  name: git
85
105
  requirement: !ruby/object:Gem::Requirement
86
106
  requirements:
87
107
  - - "~>"
88
108
  - !ruby/object:Gem::Version
89
- version: '1.3'
109
+ version: '1.7'
90
110
  type: :runtime
91
111
  prerelease: false
92
112
  version_requirements: !ruby/object:Gem::Requirement
93
113
  requirements:
94
114
  - - "~>"
95
115
  - !ruby/object:Gem::Version
96
- version: '1.3'
116
+ version: '1.7'
97
117
  - !ruby/object:Gem::Dependency
98
118
  name: gitlab
99
119
  requirement: !ruby/object:Gem::Requirement
@@ -164,11 +184,13 @@ executables:
164
184
  extensions: []
165
185
  extra_rdoc_files: []
166
186
  files:
187
+ - ".config/cucumber.yml"
188
+ - ".github/workflows/ci.yml"
189
+ - ".github/workflows/release.yml"
167
190
  - ".gitignore"
168
191
  - ".rspec"
169
192
  - ".rubocop.yml"
170
193
  - ".rubocop_todo.yml"
171
- - ".travis.yml"
172
194
  - CHANGELOG.md
173
195
  - Gemfile
174
196
  - HISTORY.md
@@ -182,24 +204,31 @@ files:
182
204
  - features/step_definitions/git_steps.rb
183
205
  - features/support/env.rb
184
206
  - features/update.feature
207
+ - features/update/bad_context.feature
208
+ - features/update/bump_version.feature
185
209
  - lib/modulesync.rb
186
210
  - lib/modulesync/cli.rb
211
+ - lib/modulesync/cli/thor.rb
187
212
  - lib/modulesync/constants.rb
188
- - lib/modulesync/git.rb
189
213
  - lib/modulesync/hook.rb
190
214
  - lib/modulesync/pr/github.rb
191
215
  - lib/modulesync/pr/gitlab.rb
216
+ - lib/modulesync/puppet_module.rb
192
217
  - lib/modulesync/renderer.rb
218
+ - lib/modulesync/repository.rb
193
219
  - lib/modulesync/settings.rb
220
+ - lib/modulesync/source_code.rb
194
221
  - lib/modulesync/util.rb
195
222
  - lib/monkey_patches.rb
196
223
  - modulesync.gemspec
224
+ - spec/helpers/faker.rb
225
+ - spec/helpers/faker/puppet_module_remote_repo.rb
197
226
  - spec/spec_helper.rb
198
227
  - spec/unit/modulesync/pr/github_spec.rb
199
228
  - spec/unit/modulesync/pr/gitlab_spec.rb
200
229
  - spec/unit/modulesync/settings_spec.rb
201
230
  - spec/unit/modulesync_spec.rb
202
- homepage: http://github.com/voxpupuli/modulesync
231
+ homepage: https://github.com/voxpupuli/modulesync
203
232
  licenses:
204
233
  - Apache-2.0
205
234
  metadata: {}
@@ -218,7 +247,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
218
247
  - !ruby/object:Gem::Version
219
248
  version: '0'
220
249
  requirements: []
221
- rubygems_version: 3.1.2
250
+ rubygems_version: 3.2.22
222
251
  signing_key:
223
252
  specification_version: 4
224
253
  summary: Puppet Module Synchronizer
@@ -228,6 +257,10 @@ test_files:
228
257
  - features/step_definitions/git_steps.rb
229
258
  - features/support/env.rb
230
259
  - features/update.feature
260
+ - features/update/bad_context.feature
261
+ - features/update/bump_version.feature
262
+ - spec/helpers/faker.rb
263
+ - spec/helpers/faker/puppet_module_remote_repo.rb
231
264
  - spec/spec_helper.rb
232
265
  - spec/unit/modulesync/pr/github_spec.rb
233
266
  - spec/unit/modulesync/pr/gitlab_spec.rb