modulesync 2.0.2 → 2.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 +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
|