modulesync 2.0.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +29 -0
- data/.github/workflows/release.yml +30 -0
- data/.rubocop_todo.yml +16 -35
- data/CHANGELOG.md +14 -0
- data/features/cli.feature +5 -2
- data/features/step_definitions/git_steps.rb +10 -0
- data/features/update.feature +4 -3
- data/features/update/bump_version.feature +87 -0
- data/lib/modulesync.rb +56 -50
- data/lib/modulesync/puppet_module.rb +37 -0
- data/lib/modulesync/repository.rb +158 -0
- data/lib/modulesync/source_code.rb +57 -0
- data/modulesync.gemspec +1 -1
- data/spec/helpers/faker/puppet_module_remote_repo.rb +6 -0
- data/spec/unit/modulesync_spec.rb +6 -2
- metadata +10 -5
- data/.travis.yml +0 -28
- data/lib/modulesync/git.rb +0 -194
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8c67abecba12a55e8bf400dbdce4899d7ae3588ec7e297c4fe3ed46b7c9ce62
|
4
|
+
data.tar.gz: 0dfcfc208e51892329bab49da6dea0b33a04a5b90dd1769a898e9f82fd8d83eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c113f5bb72bc8f77c0e07383f4ad13975915023ac865a68257eea3990fc888e193d5177d38003cf851d9ca1946ab13234c5642e75889f04cf9e52a3e3ef5f1fa
|
7
|
+
data.tar.gz: f12d610d26f07fc2ec75905a8d9637d88b063ff48f6367dbd04fdeab424052f551d28802300206b5f6ee73bda8ceeac9cf0f7bdb17b5d57f58203eaa6b6003d0
|
@@ -0,0 +1,29 @@
|
|
1
|
+
---
|
2
|
+
name: CI
|
3
|
+
on:
|
4
|
+
- pull_request
|
5
|
+
- push
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
test:
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
strategy:
|
11
|
+
fail-fast: false
|
12
|
+
matrix:
|
13
|
+
ruby:
|
14
|
+
- 2.5
|
15
|
+
- 2.6
|
16
|
+
- 2.7
|
17
|
+
- 3.0
|
18
|
+
env:
|
19
|
+
BUNDLE_WITHOUT: release
|
20
|
+
name: Ruby ${{ matrix.ruby }}
|
21
|
+
steps:
|
22
|
+
- uses: actions/checkout@v2
|
23
|
+
- name: Install Ruby ${{ matrix.ruby }}
|
24
|
+
uses: ruby/setup-ruby@v1
|
25
|
+
with:
|
26
|
+
ruby-version: ${{ matrix.ruby }}
|
27
|
+
bundler-cache: true
|
28
|
+
- name: Run tests
|
29
|
+
run: bundle exec rake test
|
@@ -0,0 +1,30 @@
|
|
1
|
+
name: Release
|
2
|
+
|
3
|
+
on:
|
4
|
+
create:
|
5
|
+
ref_type: tag
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
release:
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
if: github.repository == 'voxpupuli/modulesync'
|
11
|
+
env:
|
12
|
+
BUNDLE_WITHOUT: release
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v2
|
15
|
+
- name: Install Ruby 3.0
|
16
|
+
uses: ruby/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: '3.0'
|
19
|
+
- name: Build gem
|
20
|
+
run: gem build *.gemspec
|
21
|
+
- name: Publish gem to rubygems.org
|
22
|
+
run: gem push *.gem
|
23
|
+
env:
|
24
|
+
GEM_HOST_API_KEY: '${{ secrets.RUBYGEMS_AUTH_TOKEN }}'
|
25
|
+
- name: Setup GitHub packages access
|
26
|
+
run: |
|
27
|
+
echo ":github: Bearer ${{ secrets.GITHUB_TOKEN }}" >> ~/.gem/credentials
|
28
|
+
chmod 0600 /home/runner/.gem/credentials
|
29
|
+
- name: Publish gem to GitHub packages
|
30
|
+
run: gem push --key github --host https://rubygems.pkg.github.com/voxpupuli *.gem
|
data/.rubocop_todo.yml
CHANGED
@@ -1,70 +1,51 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on
|
3
|
+
# on 2021-04-22 16:30:35 +0200 using RuboCop version 0.50.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
-
# Offense count:
|
9
|
+
# Offense count: 1
|
10
10
|
Lint/UselessAssignment:
|
11
11
|
Exclude:
|
12
12
|
- 'lib/modulesync.rb'
|
13
|
-
- 'lib/modulesync/cli.rb'
|
14
13
|
|
15
|
-
# Offense count:
|
14
|
+
# Offense count: 10
|
16
15
|
Metrics/AbcSize:
|
17
|
-
Max:
|
16
|
+
Max: 67
|
18
17
|
|
19
|
-
# Offense count:
|
18
|
+
# Offense count: 2
|
20
19
|
# Configuration parameters: CountComments.
|
21
20
|
Metrics/ClassLength:
|
22
|
-
Max:
|
21
|
+
Max: 128
|
23
22
|
|
24
|
-
# Offense count:
|
23
|
+
# Offense count: 3
|
25
24
|
Metrics/CyclomaticComplexity:
|
26
|
-
Max:
|
25
|
+
Max: 12
|
27
26
|
|
28
|
-
# Offense count:
|
27
|
+
# Offense count: 13
|
29
28
|
# Configuration parameters: CountComments.
|
30
29
|
Metrics/MethodLength:
|
31
|
-
Max:
|
30
|
+
Max: 36
|
32
31
|
|
33
|
-
# Offense count:
|
34
|
-
# Configuration parameters: CountComments.
|
35
|
-
Metrics/ModuleLength:
|
36
|
-
Max: 140
|
37
|
-
|
38
|
-
# Offense count: 4
|
32
|
+
# Offense count: 3
|
39
33
|
Metrics/PerceivedComplexity:
|
40
|
-
Max:
|
34
|
+
Max: 13
|
41
35
|
|
42
|
-
# Offense count:
|
43
|
-
# Configuration parameters: Exclude.
|
36
|
+
# Offense count: 8
|
44
37
|
Style/Documentation:
|
45
38
|
Exclude:
|
39
|
+
- 'spec/**/*'
|
40
|
+
- 'test/**/*'
|
46
41
|
- 'lib/modulesync.rb'
|
47
42
|
- 'lib/modulesync/cli.rb'
|
48
|
-
- 'lib/modulesync/constants.rb'
|
49
|
-
- 'lib/modulesync/git.rb'
|
50
43
|
- 'lib/modulesync/hook.rb'
|
51
44
|
- 'lib/modulesync/renderer.rb'
|
52
45
|
- 'lib/modulesync/util.rb'
|
53
46
|
|
54
|
-
# Offense count: 1
|
55
|
-
Style/EachWithObject:
|
56
|
-
Exclude:
|
57
|
-
- 'lib/modulesync/util.rb'
|
58
|
-
|
59
|
-
# Offense count: 1
|
60
|
-
# Configuration parameters: MinBodyLength.
|
61
|
-
Style/GuardClause:
|
62
|
-
Exclude:
|
63
|
-
- 'lib/modulesync/cli.rb'
|
64
|
-
|
65
47
|
# Offense count: 1
|
66
48
|
# Cop supports --auto-correct.
|
67
|
-
|
68
|
-
Style/Semicolon:
|
49
|
+
Style/EachWithObject:
|
69
50
|
Exclude:
|
70
51
|
- 'lib/modulesync/util.rb'
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,20 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## [2.1.0](https://github.com/voxpupuli/modulesync/tree/2.1.0) (2021-06-15)
|
6
|
+
|
7
|
+
[Full Changelog](https://github.com/voxpupuli/modulesync/compare/2.0.2...2.1.0)
|
8
|
+
|
9
|
+
**Merged pull requests:**
|
10
|
+
|
11
|
+
- publish to github packages + test on ruby 3 [\#222](https://github.com/voxpupuli/modulesync/pull/222) ([bastelfreak](https://github.com/bastelfreak))
|
12
|
+
- Rework exception handling [\#217](https://github.com/voxpupuli/modulesync/pull/217) ([neomilium](https://github.com/neomilium))
|
13
|
+
- Split generic and specific code [\#215](https://github.com/voxpupuli/modulesync/pull/215) ([neomilium](https://github.com/neomilium))
|
14
|
+
- Refactor repository related code [\#214](https://github.com/voxpupuli/modulesync/pull/214) ([neomilium](https://github.com/neomilium))
|
15
|
+
- Tests: Add tests for bump feature [\#213](https://github.com/voxpupuli/modulesync/pull/213) ([neomilium](https://github.com/neomilium))
|
16
|
+
- Refactor puppet modules properties [\#212](https://github.com/voxpupuli/modulesync/pull/212) ([neomilium](https://github.com/neomilium))
|
17
|
+
- Switch from Travis CI to GitHub Actions [\#205](https://github.com/voxpupuli/modulesync/pull/205) ([neomilium](https://github.com/neomilium))
|
18
|
+
|
5
19
|
## [2.0.2](https://github.com/voxpupuli/modulesync/tree/2.0.2) (2021-04-03)
|
6
20
|
|
7
21
|
[Full Changelog](https://github.com/voxpupuli/modulesync/compare/2.0.1...2.0.2)
|
data/features/cli.feature
CHANGED
@@ -35,6 +35,9 @@ Feature: CLI
|
|
35
35
|
"""
|
36
36
|
And a git_base option appended to "modulesync.yml" for local tests
|
37
37
|
And a directory named "moduleroot"
|
38
|
-
When I run `msync update --noop --namespace fakenamespace`
|
38
|
+
When I run `msync update --noop --namespace fakenamespace --branch command-line-branch`
|
39
39
|
Then the exit status should be 0
|
40
|
-
And the output should
|
40
|
+
And the output should contain:
|
41
|
+
"""
|
42
|
+
Creating new branch command-line-branch
|
43
|
+
"""
|
@@ -73,3 +73,13 @@ Given 'the puppet module {string} from {string} has the default branch named {st
|
|
73
73
|
pmrr = ModuleSync::Faker::PuppetModuleRemoteRepo.new(name, namespace)
|
74
74
|
pmrr.default_branch = default_branch
|
75
75
|
end
|
76
|
+
|
77
|
+
Then('the puppet module {string} from {string} should have a tag named {string}') do |name, namespace, tag|
|
78
|
+
pmrr = ModuleSync::Faker::PuppetModuleRemoteRepo.new(name, namespace)
|
79
|
+
expect(pmrr.tags).to include(tag)
|
80
|
+
end
|
81
|
+
|
82
|
+
Then('the puppet module {string} from {string} should not have a tag named {string}') do |name, namespace, tag|
|
83
|
+
pmrr = ModuleSync::Faker::PuppetModuleRemoteRepo.new(name, namespace)
|
84
|
+
expect(pmrr.tags).not_to include(tag)
|
85
|
+
end
|
data/features/update.feature
CHANGED
@@ -300,7 +300,7 @@ Feature: update
|
|
300
300
|
"""
|
301
301
|
And the output should match:
|
302
302
|
"""
|
303
|
-
Not managing Gemfile in puppet-test
|
303
|
+
Not managing 'Gemfile' in 'puppet-test'
|
304
304
|
"""
|
305
305
|
And the exit status should be 0
|
306
306
|
And the file named "modules/fakenamespace/puppet-test/Gemfile" should contain:
|
@@ -370,7 +370,7 @@ Feature: update
|
|
370
370
|
When I run `msync update --offline`
|
371
371
|
Then the output should contain:
|
372
372
|
"""
|
373
|
-
Not managing spec/spec_helper.rb in puppet-apache
|
373
|
+
Not managing 'spec/spec_helper.rb' in 'puppet-apache'
|
374
374
|
"""
|
375
375
|
And the exit status should be 0
|
376
376
|
And the file named "modules/puppetlabs/puppet-apache/spec/spec_helper.rb" should contain:
|
@@ -461,6 +461,7 @@ Feature: update
|
|
461
461
|
And a directory named "moduleroot"
|
462
462
|
When I run `msync update --message "Running without changes"`
|
463
463
|
Then the exit status should be 0
|
464
|
+
And the stdout should contain "There were no changes in 'modules/fakenamespace/puppet-test'. Not committing."
|
464
465
|
And the puppet module "puppet-test" from "fakenamespace" should have no commits made by "Aruba"
|
465
466
|
|
466
467
|
Scenario: When specifying configurations in managed_modules.yml
|
@@ -607,7 +608,7 @@ Feature: update
|
|
607
608
|
Then the exit status should be 0
|
608
609
|
And the output should match:
|
609
610
|
"""
|
610
|
-
Not managing spec/spec_helper.rb in puppet-test
|
611
|
+
Not managing 'spec/spec_helper.rb' in 'puppet-test'
|
611
612
|
"""
|
612
613
|
And the file named "modules/fakenamespace/puppet-test/global-test.md" should contain:
|
613
614
|
"""
|
@@ -0,0 +1,87 @@
|
|
1
|
+
Feature: Bump a new version after an update
|
2
|
+
Scenario: Bump the module version, update changelog and tag it after an update that produces changes
|
3
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
4
|
+
And the puppet module "puppet-test" from "fakenamespace" has a file named "CHANGELOG.md" with:
|
5
|
+
"""
|
6
|
+
## 1965-04-14 - Release 0.4.2
|
7
|
+
"""
|
8
|
+
And a file named "config_defaults.yml" with:
|
9
|
+
"""
|
10
|
+
---
|
11
|
+
new-file:
|
12
|
+
content: aruba
|
13
|
+
"""
|
14
|
+
And a directory named "moduleroot"
|
15
|
+
And a file named "moduleroot/new-file.erb" with:
|
16
|
+
"""
|
17
|
+
<%= @configs['content'] %>
|
18
|
+
"""
|
19
|
+
When I run `msync update --message "Add new-file" --bump --changelog --tag`
|
20
|
+
Then the exit status should be 0
|
21
|
+
And the file named "modules/fakenamespace/puppet-test/new-file" should contain "aruba"
|
22
|
+
And the stdout should contain:
|
23
|
+
"""
|
24
|
+
Bumped to version 0.4.3
|
25
|
+
"""
|
26
|
+
And the stdout should contain:
|
27
|
+
"""
|
28
|
+
Tagging with 0.4.3
|
29
|
+
"""
|
30
|
+
And the file named "modules/fakenamespace/puppet-test/CHANGELOG.md" should contain "0.4.3"
|
31
|
+
And the puppet module "puppet-test" from "fakenamespace" should have 2 commits made by "Aruba"
|
32
|
+
And the puppet module "puppet-test" from "fakenamespace" should have a tag named "0.4.3"
|
33
|
+
|
34
|
+
Scenario: Bump the module version after an update that produces changes
|
35
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
36
|
+
And a file named "config_defaults.yml" with:
|
37
|
+
"""
|
38
|
+
---
|
39
|
+
new-file:
|
40
|
+
content: aruba
|
41
|
+
"""
|
42
|
+
And a directory named "moduleroot"
|
43
|
+
And a file named "moduleroot/new-file.erb" with:
|
44
|
+
"""
|
45
|
+
<%= @configs['content'] %>
|
46
|
+
"""
|
47
|
+
When I run `msync update --message "Add new-file" --bump`
|
48
|
+
Then the exit status should be 0
|
49
|
+
And the file named "modules/fakenamespace/puppet-test/new-file" should contain "aruba"
|
50
|
+
And the stdout should contain:
|
51
|
+
"""
|
52
|
+
Bumped to version 0.4.3
|
53
|
+
"""
|
54
|
+
And the puppet module "puppet-test" from "fakenamespace" should have 2 commits made by "Aruba"
|
55
|
+
And the puppet module "puppet-test" from "fakenamespace" should not have a tag named "0.4.3"
|
56
|
+
|
57
|
+
Scenario: Bump the module version with changelog update when no CHANGELOG.md is available
|
58
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
59
|
+
And a file named "config_defaults.yml" with:
|
60
|
+
"""
|
61
|
+
---
|
62
|
+
new-file:
|
63
|
+
content: aruba
|
64
|
+
"""
|
65
|
+
And a directory named "moduleroot"
|
66
|
+
And a file named "moduleroot/new-file.erb" with:
|
67
|
+
"""
|
68
|
+
<%= @configs['content'] %>
|
69
|
+
"""
|
70
|
+
When I run `msync update --message "Add new-file" --bump --changelog`
|
71
|
+
Then the exit status should be 0
|
72
|
+
And the file named "modules/fakenamespace/puppet-test/new-file" should contain "aruba"
|
73
|
+
And the stdout should contain:
|
74
|
+
"""
|
75
|
+
Bumped to version 0.4.3
|
76
|
+
No CHANGELOG.md file found, not updating.
|
77
|
+
"""
|
78
|
+
And the file named "modules/fakenamespace/puppet-test/CHANGELOG.md" should not exist
|
79
|
+
And the puppet module "puppet-test" from "fakenamespace" should have 2 commits made by "Aruba"
|
80
|
+
|
81
|
+
Scenario: Dont bump the module version after an update that produces no changes
|
82
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
83
|
+
And a directory named "moduleroot"
|
84
|
+
When I run `msync update --message "Add new-file" --bump --tag`
|
85
|
+
Then the exit status should be 0
|
86
|
+
And the puppet module "puppet-test" from "fakenamespace" should have no commits made by "Aruba"
|
87
|
+
And the puppet module "puppet-test" from "fakenamespace" should not have a tag named "0.4.3"
|
data/lib/modulesync.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'pathname'
|
3
|
+
|
3
4
|
require 'modulesync/cli'
|
4
5
|
require 'modulesync/constants'
|
5
|
-
require 'modulesync/git'
|
6
6
|
require 'modulesync/hook'
|
7
|
+
require 'modulesync/puppet_module'
|
7
8
|
require 'modulesync/renderer'
|
8
9
|
require 'modulesync/settings'
|
9
10
|
require 'modulesync/util'
|
11
|
+
|
10
12
|
require 'monkey_patches'
|
11
13
|
|
12
14
|
module ModuleSync # rubocop:disable Metrics/ModuleLength
|
15
|
+
class Error < StandardError; end
|
16
|
+
|
13
17
|
include Constants
|
14
18
|
|
15
19
|
def self.config_defaults
|
@@ -21,12 +25,12 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
21
25
|
}
|
22
26
|
end
|
23
27
|
|
24
|
-
def self.
|
25
|
-
|
28
|
+
def self.options
|
29
|
+
@options
|
26
30
|
end
|
27
31
|
|
28
|
-
def self.
|
29
|
-
File.join(
|
32
|
+
def self.local_file(config_path, file)
|
33
|
+
File.join(config_path, MODULE_FILES_DIR, file)
|
30
34
|
end
|
31
35
|
|
32
36
|
# List all template files.
|
@@ -50,7 +54,11 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
50
54
|
file_list.map { |file| file.sub(/#{path}/, '') }
|
51
55
|
end
|
52
56
|
|
53
|
-
def self.managed_modules
|
57
|
+
def self.managed_modules
|
58
|
+
config_file = config_path(options[:managed_modules_conf], options)
|
59
|
+
filter = options[:filter]
|
60
|
+
negative_filter = options[:negative_filter]
|
61
|
+
|
54
62
|
managed_modules = Util.parse_config(config_file)
|
55
63
|
if managed_modules.empty?
|
56
64
|
$stderr.puts "No modules found in #{config_file}." \
|
@@ -59,12 +67,7 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
59
67
|
end
|
60
68
|
managed_modules.select! { |m| m =~ Regexp.new(filter) } unless filter.nil?
|
61
69
|
managed_modules.reject! { |m| m =~ Regexp.new(negative_filter) } unless negative_filter.nil?
|
62
|
-
managed_modules
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.module_name(module_name, default_namespace)
|
66
|
-
return [default_namespace, module_name] unless module_name.include?('/')
|
67
|
-
ns, mod = module_name.split('/')
|
70
|
+
managed_modules.map { |given_name, options| PuppetModule.new(given_name, options) }
|
68
71
|
end
|
69
72
|
|
70
73
|
def self.hook(options)
|
@@ -78,11 +81,11 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
78
81
|
end
|
79
82
|
end
|
80
83
|
|
81
|
-
def self.manage_file(filename, settings, options)
|
84
|
+
def self.manage_file(puppet_module, filename, settings, options)
|
82
85
|
namespace = settings.additional_settings[:namespace]
|
83
86
|
module_name = settings.additional_settings[:puppet_module]
|
84
87
|
configs = settings.build_file_configs(filename)
|
85
|
-
target_file =
|
88
|
+
target_file = puppet_module.path(filename)
|
86
89
|
if configs['delete']
|
87
90
|
Renderer.remove(target_file)
|
88
91
|
else
|
@@ -92,50 +95,52 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
92
95
|
# Meta data passed to the template as @metadata[:name]
|
93
96
|
metadata = {
|
94
97
|
:module_name => module_name,
|
95
|
-
:workdir =>
|
98
|
+
:workdir => puppet_module.working_directory,
|
96
99
|
:target_file => target_file,
|
97
100
|
}
|
98
101
|
template = Renderer.render(erb, configs, metadata)
|
99
102
|
Renderer.sync(template, target_file)
|
100
|
-
rescue
|
101
|
-
$stderr.puts "Error while rendering #{filename}"
|
103
|
+
rescue StandardError => e
|
104
|
+
$stderr.puts "#{puppet_module.given_name}: Error while rendering file: '#{filename}'"
|
102
105
|
raise
|
103
106
|
end
|
104
107
|
end
|
105
108
|
end
|
106
109
|
|
107
|
-
def self.manage_module(puppet_module, module_files,
|
108
|
-
|
109
|
-
|
110
|
-
default_namespace = module_options[:namespace]
|
111
|
-
end
|
112
|
-
namespace, module_name = module_name(puppet_module, default_namespace)
|
113
|
-
git_repo = File.join(namespace, module_name)
|
114
|
-
unless options[:offline]
|
115
|
-
Git.pull(options[:git_base], git_repo, options[:branch], options[:project_root], module_options || {})
|
116
|
-
end
|
110
|
+
def self.manage_module(puppet_module, module_files, defaults)
|
111
|
+
puts "Syncing '#{puppet_module.given_name}'"
|
112
|
+
puppet_module.repository.prepare_workspace(options[:branch]) unless options[:offline]
|
117
113
|
|
118
|
-
module_configs = Util.parse_config(
|
114
|
+
module_configs = Util.parse_config puppet_module.path(MODULE_CONF_FILE)
|
119
115
|
settings = Settings.new(defaults[GLOBAL_DEFAULTS_KEY] || {},
|
120
116
|
defaults,
|
121
117
|
module_configs[GLOBAL_DEFAULTS_KEY] || {},
|
122
118
|
module_configs,
|
123
|
-
:puppet_module =>
|
119
|
+
:puppet_module => puppet_module.repository_name,
|
124
120
|
:git_base => options[:git_base],
|
125
|
-
:namespace =>
|
121
|
+
:namespace => puppet_module.repository_namespace)
|
122
|
+
|
126
123
|
settings.unmanaged_files(module_files).each do |filename|
|
127
|
-
$stdout.puts "Not managing #{filename} in #{
|
124
|
+
$stdout.puts "Not managing '#{filename}' in '#{puppet_module.given_name}'"
|
128
125
|
end
|
129
126
|
|
130
127
|
files_to_manage = settings.managed_files(module_files)
|
131
|
-
files_to_manage.each { |filename| manage_file(filename, settings, options) }
|
128
|
+
files_to_manage.each { |filename| manage_file(puppet_module, filename, settings, options) }
|
132
129
|
|
133
130
|
if options[:noop]
|
134
|
-
|
135
|
-
|
131
|
+
puts "Using no-op. Files in '#{puppet_module.given_name}' may be changed but will not be committed."
|
132
|
+
puppet_module.repository.show_changes(options)
|
133
|
+
options[:pr] && \
|
134
|
+
pr(puppet_module).manage(puppet_module.repository_namespace, puppet_module.repository_name, options)
|
136
135
|
elsif !options[:offline]
|
137
|
-
pushed =
|
138
|
-
|
136
|
+
pushed = puppet_module.repository.submit_changes(files_to_manage, options)
|
137
|
+
# Only bump/tag if pushing didn't fail (i.e. there were changes)
|
138
|
+
if pushed && options[:bump]
|
139
|
+
new = puppet_module.bump(options[:message], options[:changelog])
|
140
|
+
puppet_module.repository.tag(new, options[:tag_pattern]) if options[:tag]
|
141
|
+
end
|
142
|
+
pushed && options[:pr] && \
|
143
|
+
pr(puppet_module).manage(puppet_module.repository_namespace, puppet_module.repository_name, options)
|
139
144
|
end
|
140
145
|
end
|
141
146
|
|
@@ -148,9 +153,10 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
148
153
|
self.class.config_path(file, options)
|
149
154
|
end
|
150
155
|
|
151
|
-
def self.update(
|
152
|
-
options = config_defaults.merge(
|
156
|
+
def self.update(cli_options)
|
157
|
+
@options = config_defaults.merge(cli_options)
|
153
158
|
defaults = Util.parse_config(config_path(CONF_FILE, options))
|
159
|
+
|
154
160
|
if options[:pr]
|
155
161
|
unless options[:branch]
|
156
162
|
$stderr.puts 'A branch must be specified with --branch to use --pr!'
|
@@ -164,28 +170,28 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
164
170
|
local_files = find_template_files(local_template_dir)
|
165
171
|
module_files = relative_names(local_files, local_template_dir)
|
166
172
|
|
167
|
-
managed_modules = self.managed_modules(config_path(options[:managed_modules_conf], options),
|
168
|
-
options[:filter],
|
169
|
-
options[:negative_filter])
|
170
|
-
|
171
173
|
errors = false
|
172
174
|
# managed_modules is either an array or a hash
|
173
|
-
managed_modules.each do |puppet_module
|
175
|
+
managed_modules.each do |puppet_module|
|
174
176
|
begin
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
$stderr.puts "
|
177
|
+
manage_module(puppet_module, module_files, defaults)
|
178
|
+
rescue ModuleSync::Error, Git::GitExecuteError => e
|
179
|
+
message = e.message || "Error during '#{options[:command]}'"
|
180
|
+
$stderr.puts "#{puppet_module.given_name}: #{message}"
|
181
|
+
exit 1 unless options[:skip_broken]
|
182
|
+
errors = true
|
183
|
+
$stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed"
|
184
|
+
rescue StandardError => e
|
179
185
|
raise unless options[:skip_broken]
|
180
186
|
errors = true
|
181
|
-
$stdout.puts "Skipping #{puppet_module} as update process failed"
|
187
|
+
$stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed"
|
182
188
|
end
|
183
189
|
end
|
184
190
|
exit 1 if errors && options[:fail_on_warnings]
|
185
191
|
end
|
186
192
|
|
187
|
-
def self.pr(
|
188
|
-
module_options
|
193
|
+
def self.pr(puppet_module)
|
194
|
+
module_options = puppet_module.options
|
189
195
|
github_conf = module_options[:github]
|
190
196
|
gitlab_conf = module_options[:gitlab]
|
191
197
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'puppet_blacksmith'
|
2
|
+
|
3
|
+
require 'modulesync/source_code'
|
4
|
+
|
5
|
+
module ModuleSync
|
6
|
+
# Provide methods to manipulate puppet module code
|
7
|
+
class PuppetModule < SourceCode
|
8
|
+
def update_changelog(version, message)
|
9
|
+
changelog = path('CHANGELOG.md')
|
10
|
+
if File.exist?(changelog)
|
11
|
+
puts "Updating #{changelog} for version #{version}"
|
12
|
+
changes = File.readlines(changelog)
|
13
|
+
File.open(changelog, 'w') do |f|
|
14
|
+
date = Time.now.strftime('%Y-%m-%d')
|
15
|
+
f.puts "## #{date} - Release #{version}\n\n"
|
16
|
+
f.puts "#{message}\n\n"
|
17
|
+
# Add old lines again
|
18
|
+
f.puts changes
|
19
|
+
end
|
20
|
+
repository.git.add('CHANGELOG.md')
|
21
|
+
else
|
22
|
+
puts 'No CHANGELOG.md file found, not updating.'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def bump(message, changelog = false)
|
27
|
+
m = Blacksmith::Modulefile.new path('metadata.json')
|
28
|
+
new = m.bump!
|
29
|
+
puts "Bumped to version #{new}"
|
30
|
+
repository.git.add('metadata.json')
|
31
|
+
update_changelog(new, message) if changelog
|
32
|
+
repository.git.commit("Release version #{new}")
|
33
|
+
repository.git.push
|
34
|
+
new
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'git'
|
2
|
+
|
3
|
+
module ModuleSync
|
4
|
+
# Wrapper for Git in ModuleSync context
|
5
|
+
class Repository
|
6
|
+
def initialize(directory:, remote:)
|
7
|
+
@directory = directory
|
8
|
+
@remote = remote
|
9
|
+
end
|
10
|
+
|
11
|
+
def git
|
12
|
+
@git ||= Git.open @directory
|
13
|
+
end
|
14
|
+
|
15
|
+
# This is an alias to minimize code alteration
|
16
|
+
def repo
|
17
|
+
git
|
18
|
+
end
|
19
|
+
|
20
|
+
def remote_branch_exists?(branch)
|
21
|
+
repo.branches.remote.collect(&:name).include?(branch)
|
22
|
+
end
|
23
|
+
|
24
|
+
def local_branch_exists?(branch)
|
25
|
+
repo.branches.local.collect(&:name).include?(branch)
|
26
|
+
end
|
27
|
+
|
28
|
+
def remote_branch_differ?(local_branch, remote_branch)
|
29
|
+
!remote_branch_exists?(remote_branch) ||
|
30
|
+
repo.diff("#{local_branch}..origin/#{remote_branch}").any?
|
31
|
+
end
|
32
|
+
|
33
|
+
def default_branch
|
34
|
+
symbolic_ref = repo.branches.find { |b| b.full =~ %r{remotes/origin/HEAD} }
|
35
|
+
return unless symbolic_ref
|
36
|
+
%r{remotes/origin/HEAD\s+->\s+origin/(?<branch>.+?)$}.match(symbolic_ref.full)[:branch]
|
37
|
+
end
|
38
|
+
|
39
|
+
def switch_branch(branch)
|
40
|
+
unless branch
|
41
|
+
branch = default_branch
|
42
|
+
puts "Using repository's default branch: #{branch}"
|
43
|
+
end
|
44
|
+
return if repo.current_branch == branch
|
45
|
+
|
46
|
+
if local_branch_exists?(branch)
|
47
|
+
puts "Switching to branch #{branch}"
|
48
|
+
repo.checkout(branch)
|
49
|
+
elsif remote_branch_exists?(branch)
|
50
|
+
puts "Creating local branch #{branch} from origin/#{branch}"
|
51
|
+
repo.checkout("origin/#{branch}")
|
52
|
+
repo.branch(branch).checkout
|
53
|
+
else
|
54
|
+
repo.checkout('origin/master')
|
55
|
+
puts "Creating new branch #{branch}"
|
56
|
+
repo.branch(branch).checkout
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def prepare_workspace(branch)
|
61
|
+
# Repo needs to be cloned in the cwd
|
62
|
+
if !Dir.exist?("#{@directory}/.git")
|
63
|
+
puts 'Cloning repository fresh'
|
64
|
+
puts "Cloning from '#{@remote}'"
|
65
|
+
@git = Git.clone(@remote, @directory)
|
66
|
+
switch_branch(branch)
|
67
|
+
# Repo already cloned, check out master and override local changes
|
68
|
+
else
|
69
|
+
# Some versions of git can't properly handle managing a repo from outside the repo directory
|
70
|
+
Dir.chdir(@directory) do
|
71
|
+
puts "Overriding any local changes to repository in '#{@directory}'"
|
72
|
+
@git = Git.open('.')
|
73
|
+
repo.fetch
|
74
|
+
repo.reset_hard
|
75
|
+
switch_branch(branch)
|
76
|
+
git.pull('origin', branch) if remote_branch_exists?(branch)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def tag(version, tag_pattern)
|
82
|
+
tag = tag_pattern % version
|
83
|
+
puts "Tagging with #{tag}"
|
84
|
+
repo.add_tag(tag)
|
85
|
+
repo.push('origin', tag)
|
86
|
+
end
|
87
|
+
|
88
|
+
def checkout_branch(branch)
|
89
|
+
selected_branch = branch || repo.current_branch || 'master'
|
90
|
+
repo.branch(selected_branch).checkout
|
91
|
+
selected_branch
|
92
|
+
end
|
93
|
+
|
94
|
+
# Git add/rm, git commit, git push
|
95
|
+
def submit_changes(files, options)
|
96
|
+
message = options[:message]
|
97
|
+
branch = checkout_branch(options[:branch])
|
98
|
+
files.each do |file|
|
99
|
+
if repo.status.deleted.include?(file)
|
100
|
+
repo.remove(file)
|
101
|
+
elsif File.exist?("#{@directory}/#{file}")
|
102
|
+
repo.add(file)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
begin
|
106
|
+
opts_commit = {}
|
107
|
+
opts_push = {}
|
108
|
+
opts_commit = { :amend => true } if options[:amend]
|
109
|
+
opts_push = { :force => true } if options[:force]
|
110
|
+
if options[:pre_commit_script]
|
111
|
+
script = "#{File.dirname(File.dirname(__FILE__))}/../contrib/#{options[:pre_commit_script]}"
|
112
|
+
`#{script} #{@directory}`
|
113
|
+
end
|
114
|
+
repo.commit(message, opts_commit)
|
115
|
+
if options[:remote_branch]
|
116
|
+
if remote_branch_differ?(branch, options[:remote_branch])
|
117
|
+
repo.push('origin', "#{branch}:#{options[:remote_branch]}", opts_push)
|
118
|
+
end
|
119
|
+
else
|
120
|
+
repo.push('origin', branch, opts_push)
|
121
|
+
end
|
122
|
+
rescue Git::GitExecuteError => e
|
123
|
+
raise unless e.message.match?(/working (directory|tree) clean/)
|
124
|
+
|
125
|
+
puts "There were no changes in '#{@directory}'. Not committing."
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
|
129
|
+
true
|
130
|
+
end
|
131
|
+
|
132
|
+
# Needed because of a bug in the git gem that lists ignored files as
|
133
|
+
# untracked under some circumstances
|
134
|
+
# https://github.com/schacon/ruby-git/issues/130
|
135
|
+
def untracked_unignored_files
|
136
|
+
ignore_path = "#{@directory}/.gitignore"
|
137
|
+
ignored = File.exist?(ignore_path) ? File.read(ignore_path).split : []
|
138
|
+
repo.status.untracked.keep_if { |f, _| ignored.none? { |i| File.fnmatch(i, f) } }
|
139
|
+
end
|
140
|
+
|
141
|
+
def show_changes(options)
|
142
|
+
checkout_branch(options[:branch])
|
143
|
+
|
144
|
+
puts 'Files changed:'
|
145
|
+
repo.diff('HEAD', '--').each do |diff|
|
146
|
+
puts diff.patch
|
147
|
+
end
|
148
|
+
|
149
|
+
puts 'Files added:'
|
150
|
+
untracked_unignored_files.each_key do |file|
|
151
|
+
puts file
|
152
|
+
end
|
153
|
+
|
154
|
+
puts "\n\n"
|
155
|
+
puts '--------------------------------'
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -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
|
data/modulesync.gemspec
CHANGED
@@ -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 = '2.0
|
6
|
+
spec.version = '2.1.0'
|
7
7
|
spec.authors = ['Vox Pupuli']
|
8
8
|
spec.email = ['voxpupuli@groups.io']
|
9
9
|
spec.summary = 'Puppet Module Synchronizer'
|
@@ -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(
|
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(
|
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,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: modulesync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.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: 2021-
|
11
|
+
date: 2021-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aruba
|
@@ -165,11 +165,12 @@ extensions: []
|
|
165
165
|
extra_rdoc_files: []
|
166
166
|
files:
|
167
167
|
- ".config/cucumber.yml"
|
168
|
+
- ".github/workflows/ci.yml"
|
169
|
+
- ".github/workflows/release.yml"
|
168
170
|
- ".gitignore"
|
169
171
|
- ".rspec"
|
170
172
|
- ".rubocop.yml"
|
171
173
|
- ".rubocop_todo.yml"
|
172
|
-
- ".travis.yml"
|
173
174
|
- CHANGELOG.md
|
174
175
|
- Gemfile
|
175
176
|
- HISTORY.md
|
@@ -184,16 +185,19 @@ files:
|
|
184
185
|
- features/support/env.rb
|
185
186
|
- features/update.feature
|
186
187
|
- features/update/bad_context.feature
|
188
|
+
- features/update/bump_version.feature
|
187
189
|
- lib/modulesync.rb
|
188
190
|
- lib/modulesync/cli.rb
|
189
191
|
- lib/modulesync/cli/thor.rb
|
190
192
|
- lib/modulesync/constants.rb
|
191
|
-
- lib/modulesync/git.rb
|
192
193
|
- lib/modulesync/hook.rb
|
193
194
|
- lib/modulesync/pr/github.rb
|
194
195
|
- lib/modulesync/pr/gitlab.rb
|
196
|
+
- lib/modulesync/puppet_module.rb
|
195
197
|
- lib/modulesync/renderer.rb
|
198
|
+
- lib/modulesync/repository.rb
|
196
199
|
- lib/modulesync/settings.rb
|
200
|
+
- lib/modulesync/source_code.rb
|
197
201
|
- lib/modulesync/util.rb
|
198
202
|
- lib/monkey_patches.rb
|
199
203
|
- modulesync.gemspec
|
@@ -223,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
223
227
|
- !ruby/object:Gem::Version
|
224
228
|
version: '0'
|
225
229
|
requirements: []
|
226
|
-
rubygems_version: 3.
|
230
|
+
rubygems_version: 3.2.15
|
227
231
|
signing_key:
|
228
232
|
specification_version: 4
|
229
233
|
summary: Puppet Module Synchronizer
|
@@ -234,6 +238,7 @@ test_files:
|
|
234
238
|
- features/support/env.rb
|
235
239
|
- features/update.feature
|
236
240
|
- features/update/bad_context.feature
|
241
|
+
- features/update/bump_version.feature
|
237
242
|
- spec/helpers/faker.rb
|
238
243
|
- spec/helpers/faker/puppet_module_remote_repo.rb
|
239
244
|
- spec/spec_helper.rb
|
data/.travis.yml
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sudo: false
|
3
|
-
language: ruby
|
4
|
-
cache: bundler
|
5
|
-
dist: focal
|
6
|
-
script: 'bundle exec rake test'
|
7
|
-
bundler_args: --without release
|
8
|
-
rvm:
|
9
|
-
- 2.5
|
10
|
-
- 2.6
|
11
|
-
- 2.7
|
12
|
-
notifications:
|
13
|
-
email: false
|
14
|
-
irc:
|
15
|
-
on_success: always
|
16
|
-
on_failure: always
|
17
|
-
channels:
|
18
|
-
- "chat.freenode.org#voxpupuli-notifications"
|
19
|
-
deploy:
|
20
|
-
provider: rubygems
|
21
|
-
api_key:
|
22
|
-
secure: "Tbf1EbLEobIIox+fftJZADZsfQQ6kl0urcMNetK7NJzFo/negD/WyJIUj3kro/B7buyYADEjTui/JR4o8EPbugfM3ie5vYOd5k3AesSzbdr4BSwGe/cGbGOB7/PZuGfFLkb94/FiCU2mIwibkbh1rHWGlBoPj7ntL0+5ZtdvsM4="
|
23
|
-
gem: modulesync
|
24
|
-
on:
|
25
|
-
rvm: 2.7
|
26
|
-
tags: true
|
27
|
-
all_branches: true
|
28
|
-
repo: voxpupuli/modulesync
|
data/lib/modulesync/git.rb
DELETED
@@ -1,194 +0,0 @@
|
|
1
|
-
require 'git'
|
2
|
-
require 'puppet_blacksmith'
|
3
|
-
|
4
|
-
module ModuleSync
|
5
|
-
module Git # rubocop:disable Metrics/ModuleLength
|
6
|
-
include Constants
|
7
|
-
|
8
|
-
def self.remote_branch_exists?(repo, branch)
|
9
|
-
repo.branches.remote.collect(&:name).include?(branch)
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.local_branch_exists?(repo, branch)
|
13
|
-
repo.branches.local.collect(&:name).include?(branch)
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.remote_branch_differ?(repo, local_branch, remote_branch)
|
17
|
-
!remote_branch_exists?(repo, remote_branch) ||
|
18
|
-
repo.diff("#{local_branch}..origin/#{remote_branch}").any?
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.default_branch(repo)
|
22
|
-
symbolic_ref = repo.branches.find { |b| b.full =~ %r{remotes/origin/HEAD} }
|
23
|
-
return unless symbolic_ref
|
24
|
-
%r{remotes/origin/HEAD\s+->\s+origin/(?<branch>.+?)$}.match(symbolic_ref.full)[:branch]
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.switch_branch(repo, branch)
|
28
|
-
unless branch
|
29
|
-
branch = default_branch(repo)
|
30
|
-
puts "Using repository's default branch: #{branch}"
|
31
|
-
end
|
32
|
-
return if repo.current_branch == branch
|
33
|
-
|
34
|
-
if local_branch_exists?(repo, branch)
|
35
|
-
puts "Switching to branch #{branch}"
|
36
|
-
repo.checkout(branch)
|
37
|
-
elsif remote_branch_exists?(repo, branch)
|
38
|
-
puts "Creating local branch #{branch} from origin/#{branch}"
|
39
|
-
repo.checkout("origin/#{branch}")
|
40
|
-
repo.branch(branch).checkout
|
41
|
-
else
|
42
|
-
repo.checkout('origin/master')
|
43
|
-
puts "Creating new branch #{branch}"
|
44
|
-
repo.branch(branch).checkout
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.pull(git_base, name, branch, project_root, opts)
|
49
|
-
puts "Syncing #{name}"
|
50
|
-
Dir.mkdir(project_root) unless Dir.exist?(project_root)
|
51
|
-
|
52
|
-
# Repo needs to be cloned in the cwd
|
53
|
-
if !Dir.exist?("#{project_root}/#{name}") || !Dir.exist?("#{project_root}/#{name}/.git")
|
54
|
-
puts 'Cloning repository fresh'
|
55
|
-
remote = opts[:remote] || (git_base.start_with?('file://') ? "#{git_base}#{name}" : "#{git_base}#{name}.git")
|
56
|
-
local = "#{project_root}/#{name}"
|
57
|
-
puts "Cloning from #{remote}"
|
58
|
-
repo = ::Git.clone(remote, local)
|
59
|
-
switch_branch(repo, branch)
|
60
|
-
# Repo already cloned, check out master and override local changes
|
61
|
-
else
|
62
|
-
# Some versions of git can't properly handle managing a repo from outside the repo directory
|
63
|
-
Dir.chdir("#{project_root}/#{name}") do
|
64
|
-
puts "Overriding any local changes to repositories in #{project_root}"
|
65
|
-
repo = ::Git.open('.')
|
66
|
-
repo.fetch
|
67
|
-
repo.reset_hard
|
68
|
-
switch_branch(repo, branch)
|
69
|
-
repo.pull('origin', branch) if remote_branch_exists?(repo, branch)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.update_changelog(repo, version, message, module_root)
|
75
|
-
changelog = "#{module_root}/CHANGELOG.md"
|
76
|
-
if File.exist?(changelog)
|
77
|
-
puts "Updating #{changelog} for version #{version}"
|
78
|
-
changes = File.readlines(changelog)
|
79
|
-
File.open(changelog, 'w') do |f|
|
80
|
-
date = Time.now.strftime('%Y-%m-%d')
|
81
|
-
f.puts "## #{date} - Release #{version}\n\n"
|
82
|
-
f.puts "#{message}\n\n"
|
83
|
-
# Add old lines again
|
84
|
-
f.puts changes
|
85
|
-
end
|
86
|
-
repo.add('CHANGELOG.md')
|
87
|
-
else
|
88
|
-
puts 'No CHANGELOG.md file found, not updating.'
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.bump(repo, m, message, module_root, changelog = false)
|
93
|
-
new = m.bump!
|
94
|
-
puts "Bumped to version #{new}"
|
95
|
-
repo.add('metadata.json')
|
96
|
-
update_changelog(repo, new, message, module_root) if changelog
|
97
|
-
repo.commit("Release version #{new}")
|
98
|
-
repo.push
|
99
|
-
new
|
100
|
-
end
|
101
|
-
|
102
|
-
def self.tag(repo, version, tag_pattern)
|
103
|
-
tag = tag_pattern % version
|
104
|
-
puts "Tagging with #{tag}"
|
105
|
-
repo.add_tag(tag)
|
106
|
-
repo.push('origin', tag)
|
107
|
-
end
|
108
|
-
|
109
|
-
def self.checkout_branch(repo, branch)
|
110
|
-
selected_branch = branch || repo.current_branch || 'master'
|
111
|
-
repo.branch(selected_branch).checkout
|
112
|
-
selected_branch
|
113
|
-
end
|
114
|
-
private_class_method :checkout_branch
|
115
|
-
|
116
|
-
# Git add/rm, git commit, git push
|
117
|
-
def self.update(name, files, options)
|
118
|
-
module_root = "#{options[:project_root]}/#{name}"
|
119
|
-
message = options[:message]
|
120
|
-
repo = ::Git.open(module_root)
|
121
|
-
branch = checkout_branch(repo, options[:branch])
|
122
|
-
files.each do |file|
|
123
|
-
if repo.status.deleted.include?(file)
|
124
|
-
repo.remove(file)
|
125
|
-
elsif File.exist?("#{module_root}/#{file}")
|
126
|
-
repo.add(file)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
begin
|
130
|
-
opts_commit = {}
|
131
|
-
opts_push = {}
|
132
|
-
opts_commit = { :amend => true } if options[:amend]
|
133
|
-
opts_push = { :force => true } if options[:force]
|
134
|
-
if options[:pre_commit_script]
|
135
|
-
script = "#{File.dirname(File.dirname(__FILE__))}/../contrib/#{options[:pre_commit_script]}"
|
136
|
-
`#{script} #{module_root}`
|
137
|
-
end
|
138
|
-
repo.commit(message, opts_commit)
|
139
|
-
if options[:remote_branch]
|
140
|
-
if remote_branch_differ?(repo, branch, options[:remote_branch])
|
141
|
-
repo.push('origin', "#{branch}:#{options[:remote_branch]}", opts_push)
|
142
|
-
end
|
143
|
-
else
|
144
|
-
repo.push('origin', branch, opts_push)
|
145
|
-
end
|
146
|
-
# Only bump/tag if pushing didn't fail (i.e. there were changes)
|
147
|
-
m = Blacksmith::Modulefile.new("#{module_root}/metadata.json")
|
148
|
-
if options[:bump]
|
149
|
-
new = bump(repo, m, message, module_root, options[:changelog])
|
150
|
-
tag(repo, new, options[:tag_pattern]) if options[:tag]
|
151
|
-
end
|
152
|
-
rescue ::Git::GitExecuteError => git_error
|
153
|
-
if git_error.message.match?(/working (directory|tree) clean/)
|
154
|
-
puts "There were no files to update in #{name}. Not committing."
|
155
|
-
return false
|
156
|
-
else
|
157
|
-
puts git_error
|
158
|
-
raise
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
true
|
163
|
-
end
|
164
|
-
|
165
|
-
# Needed because of a bug in the git gem that lists ignored files as
|
166
|
-
# untracked under some circumstances
|
167
|
-
# https://github.com/schacon/ruby-git/issues/130
|
168
|
-
def self.untracked_unignored_files(repo)
|
169
|
-
ignore_path = "#{repo.dir.path}/.gitignore"
|
170
|
-
ignored = File.exist?(ignore_path) ? File.read(ignore_path).split : []
|
171
|
-
repo.status.untracked.keep_if { |f, _| ignored.none? { |i| File.fnmatch(i, f) } }
|
172
|
-
end
|
173
|
-
|
174
|
-
def self.update_noop(name, options)
|
175
|
-
puts "Using no-op. Files in #{name} may be changed but will not be committed."
|
176
|
-
|
177
|
-
repo = ::Git.open("#{options[:project_root]}/#{name}")
|
178
|
-
checkout_branch(repo, options[:branch])
|
179
|
-
|
180
|
-
puts 'Files changed:'
|
181
|
-
repo.diff('HEAD', '--').each do |diff|
|
182
|
-
puts diff.patch
|
183
|
-
end
|
184
|
-
|
185
|
-
puts 'Files added:'
|
186
|
-
untracked_unignored_files(repo).each_key do |file|
|
187
|
-
puts file
|
188
|
-
end
|
189
|
-
|
190
|
-
puts "\n\n"
|
191
|
-
puts '--------------------------------'
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|