modulesync 4.5.0 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +5 -5
- data/.github/workflows/labeler.yml +1 -1
- data/.github/workflows/release.yml +3 -3
- data/CHANGELOG.md +18 -2
- data/README.md +17 -0
- data/features/cli.feature +5 -0
- data/lib/modulesync/cli.rb +8 -0
- data/lib/modulesync/puppet_module.rb +2 -2
- data/lib/modulesync/repository.rb +19 -7
- data/lib/modulesync/version.rb +1 -1
- data/lib/modulesync.rb +3 -2
- data/spec/unit/module_sync/repository_spec.rb +75 -0
- data/spec/unit/module_sync_spec.rb +12 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b2b460c8084356169de564afc59efed808706c5a08aa3501f8fe1f6f3930fbd3
|
|
4
|
+
data.tar.gz: 637c12c11b80a3545949cb8e28e3c941e522d9b41fb2a7ba180a9a51e832b223
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 431a276bdaa1fef73a7cc9d670d5c7ee398c7eb82a84e32dd9ce14959d7f001656f7b8bada9d906f76d42ae51affa9298e9b03d629c54ae497b03485d63cc4c1
|
|
7
|
+
data.tar.gz: e9a0a7842ff1f908a7ffc81f99045186068919b052c5ffd0f4ed886d50ae1e6fd4338726db141333e0326221b79077b837e7e65da0f93bd032677f20c218e8ee
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -16,16 +16,16 @@ jobs:
|
|
|
16
16
|
outputs:
|
|
17
17
|
ruby: ${{ steps.ruby.outputs.versions }}
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
20
20
|
- name: Setup ruby
|
|
21
|
-
uses: ruby/setup-ruby@
|
|
21
|
+
uses: ruby/setup-ruby@e8944e80fb94b20106697132f8c20c665fab29e9 # v1.325.0
|
|
22
22
|
with:
|
|
23
23
|
ruby-version: "3.4"
|
|
24
24
|
bundler-cache: true
|
|
25
25
|
- name: Run linter
|
|
26
26
|
run: bundle exec rake rubocop
|
|
27
27
|
- id: ruby
|
|
28
|
-
uses: voxpupuli/ruby-version@
|
|
28
|
+
uses: voxpupuli/ruby-version@be0467ce7366d206b2e87f5b7a032a030120b7cb # 2.0.0
|
|
29
29
|
|
|
30
30
|
test:
|
|
31
31
|
name: "Ruby ${{ matrix.ruby }}"
|
|
@@ -36,9 +36,9 @@ jobs:
|
|
|
36
36
|
matrix:
|
|
37
37
|
ruby: ${{ fromJSON(needs.rubocop_and_matrix.outputs.ruby) }}
|
|
38
38
|
steps:
|
|
39
|
-
- uses: actions/checkout@
|
|
39
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
40
40
|
- name: Install Ruby ${{ matrix.ruby }}
|
|
41
|
-
uses: ruby/setup-ruby@
|
|
41
|
+
uses: ruby/setup-ruby@e8944e80fb94b20106697132f8c20c665fab29e9 # v1.325.0
|
|
42
42
|
with:
|
|
43
43
|
ruby-version: ${{ matrix.ruby }}
|
|
44
44
|
bundler-cache: true
|
|
@@ -15,9 +15,9 @@ jobs:
|
|
|
15
15
|
name: Build the gem
|
|
16
16
|
runs-on: ubuntu-24.04
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
19
19
|
- name: Install Ruby
|
|
20
|
-
uses: ruby/setup-ruby@
|
|
20
|
+
uses: ruby/setup-ruby@e8944e80fb94b20106697132f8c20c665fab29e9 # v1.325.0
|
|
21
21
|
with:
|
|
22
22
|
ruby-version: 'ruby'
|
|
23
23
|
- name: Build gem
|
|
@@ -96,7 +96,7 @@ jobs:
|
|
|
96
96
|
with:
|
|
97
97
|
name: gem-artifact
|
|
98
98
|
- name: Install Ruby
|
|
99
|
-
uses: ruby/setup-ruby@
|
|
99
|
+
uses: ruby/setup-ruby@e8944e80fb94b20106697132f8c20c665fab29e9 # v1.325.0
|
|
100
100
|
with:
|
|
101
101
|
ruby-version: 'ruby'
|
|
102
102
|
- name: Wait for release to propagate
|
data/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [4.
|
|
5
|
+
## [4.6.1](https://github.com/voxpupuli/modulesync/tree/4.6.1) (2026-09-25)
|
|
6
6
|
|
|
7
|
-
[Full Changelog](https://github.com/voxpupuli/modulesync/compare/v4.
|
|
7
|
+
[Full Changelog](https://github.com/voxpupuli/modulesync/compare/v4.6.0...4.6.1)
|
|
8
|
+
|
|
9
|
+
**Fixed bugs:**
|
|
10
|
+
|
|
11
|
+
- fix: rebase existing remote branches after a fresh clone [\#376](https://github.com/voxpupuli/modulesync/pull/376) ([rwaffen](https://github.com/rwaffen))
|
|
12
|
+
|
|
13
|
+
## [v4.6.0](https://github.com/voxpupuli/modulesync/tree/v4.6.0) (2026-07-31)
|
|
14
|
+
|
|
15
|
+
[Full Changelog](https://github.com/voxpupuli/modulesync/compare/v4.5.0...v4.6.0)
|
|
16
|
+
|
|
17
|
+
**Implemented enhancements:**
|
|
18
|
+
|
|
19
|
+
- feat: add support for cryptographic signing and signoff options in commits and tags [\#368](https://github.com/voxpupuli/modulesync/pull/368) ([rwaffen](https://github.com/rwaffen))
|
|
20
|
+
|
|
21
|
+
## [v4.5.0](https://github.com/voxpupuli/modulesync/tree/v4.5.0) (2026-07-15)
|
|
22
|
+
|
|
23
|
+
[Full Changelog](https://github.com/voxpupuli/modulesync/compare/v4.4.0...v4.5.0)
|
|
8
24
|
|
|
9
25
|
**Implemented enhancements:**
|
|
10
26
|
|
data/README.md
CHANGED
|
@@ -166,6 +166,17 @@ Not required for gerrit.
|
|
|
166
166
|
msync update --amend --force
|
|
167
167
|
```
|
|
168
168
|
|
|
169
|
+
Use `--sign` to cryptographically sign commits and tags with Git's configured signing key and backend.
|
|
170
|
+
ModuleSync only passes Git's signing flags (`git commit --gpg-sign` and `git tag --sign`).
|
|
171
|
+
It does not configure the signing key, format, or backend; users must configure these settings in their Git configuration.
|
|
172
|
+
Use `--signoff` to add Git's `Signed-off-by` trailer.
|
|
173
|
+
The options can be combined and also apply to the release commit created by `--bump`.
|
|
174
|
+
When combined with `--tag`, `--sign` creates signed annotated tags using `git tag --sign`.
|
|
175
|
+
|
|
176
|
+
```shell
|
|
177
|
+
msync update -m "Commit message" --sign --signoff
|
|
178
|
+
```
|
|
179
|
+
|
|
169
180
|
#### Automating Updates
|
|
170
181
|
|
|
171
182
|
You can install a pre-push git hook to automatically clone, update, and push modules upon pushing changes to the configuration directory.
|
|
@@ -365,6 +376,12 @@ If you wish to tag the modified repositories with the newly bumped version, you
|
|
|
365
376
|
msync update -m "Commit message" --bump --tag
|
|
366
377
|
```
|
|
367
378
|
|
|
379
|
+
Add `--sign` to cryptographically sign both the release commit and tag:
|
|
380
|
+
|
|
381
|
+
```shell
|
|
382
|
+
msync update -m "Commit message" --bump --tag --sign
|
|
383
|
+
```
|
|
384
|
+
|
|
368
385
|
#### Setting the tag pattern
|
|
369
386
|
|
|
370
387
|
You can also set the format of the tag to be used (`printf`-formatted) by setting the `tag_pattern` option:
|
data/features/cli.feature
CHANGED
|
@@ -28,6 +28,11 @@ Feature: CLI
|
|
|
28
28
|
msync clone
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
|
+
Scenario: Update help lists commit signing options
|
|
32
|
+
When I successfully run `msync update --help`
|
|
33
|
+
Then the output should match /--sign/
|
|
34
|
+
And the output should match /--signoff/
|
|
35
|
+
|
|
31
36
|
Scenario: When overriding a setting from the config file on the command line
|
|
32
37
|
Given a puppet module "puppet-test" from "fakenamespace"
|
|
33
38
|
And a file named "managed_modules.yml" with:
|
data/lib/modulesync/cli.rb
CHANGED
|
@@ -88,6 +88,14 @@ module ModuleSync
|
|
|
88
88
|
type: :boolean,
|
|
89
89
|
desc: 'Amend previous commit',
|
|
90
90
|
default: false
|
|
91
|
+
option :sign,
|
|
92
|
+
type: :boolean,
|
|
93
|
+
desc: 'Cryptographically sign commits and tags',
|
|
94
|
+
default: false
|
|
95
|
+
option :signoff,
|
|
96
|
+
type: :boolean,
|
|
97
|
+
desc: 'Add a Signed-off-by trailer to commits',
|
|
98
|
+
default: false
|
|
91
99
|
option :force,
|
|
92
100
|
type: :boolean,
|
|
93
101
|
desc: 'Force push amended commit',
|
|
@@ -25,13 +25,13 @@ module ModuleSync
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def bump(message, changelog = false)
|
|
28
|
+
def bump(message, changelog = false, signing_options = {})
|
|
29
29
|
m = Blacksmith::Modulefile.new path('metadata.json')
|
|
30
30
|
new = m.bump!
|
|
31
31
|
puts "Bumped to version #{new}"
|
|
32
32
|
repository.git.add('metadata.json')
|
|
33
33
|
update_changelog(new, message) if changelog
|
|
34
|
-
repository.
|
|
34
|
+
repository.commit_changes("Release version #{new}", signing_options)
|
|
35
35
|
repository.git.push
|
|
36
36
|
new
|
|
37
37
|
end
|
|
@@ -105,16 +105,17 @@ module ModuleSync
|
|
|
105
105
|
puts "Overriding any local changes to repository in '#{@directory}'"
|
|
106
106
|
git.fetch 'origin', prune: true unless operate_offline
|
|
107
107
|
git.reset_hard
|
|
108
|
-
rebase_target = remote_default_branch if rebase && !operate_offline
|
|
109
108
|
switch(branch: branch)
|
|
110
109
|
git.pull('origin', branch) if !operate_offline && remote_branch_exists?(branch)
|
|
111
|
-
rebase_onto(rebase_target) if rebase_target
|
|
112
110
|
else
|
|
113
111
|
raise ModuleSync::Error, 'Unable to clone in offline mode.' if operate_offline
|
|
114
112
|
|
|
115
113
|
clone
|
|
116
114
|
switch(branch: branch)
|
|
117
115
|
end
|
|
116
|
+
|
|
117
|
+
rebase_target = remote_default_branch if rebase && !operate_offline
|
|
118
|
+
rebase_onto(rebase_target) if rebase_target
|
|
118
119
|
end
|
|
119
120
|
|
|
120
121
|
def rebase_onto(branch)
|
|
@@ -165,10 +166,10 @@ module ModuleSync
|
|
|
165
166
|
end
|
|
166
167
|
end
|
|
167
168
|
|
|
168
|
-
def tag(version, tag_pattern)
|
|
169
|
+
def tag(version, tag_pattern, sign: false)
|
|
169
170
|
tag = tag_pattern % version
|
|
170
171
|
puts "Tagging with #{tag}"
|
|
171
|
-
repo.add_tag(tag)
|
|
172
|
+
repo.add_tag(tag, sign: sign)
|
|
172
173
|
repo.push('origin', tag)
|
|
173
174
|
end
|
|
174
175
|
|
|
@@ -178,6 +179,19 @@ module ModuleSync
|
|
|
178
179
|
selected_branch
|
|
179
180
|
end
|
|
180
181
|
|
|
182
|
+
def commit_changes(message, options)
|
|
183
|
+
commit_options = {}
|
|
184
|
+
commit_options[:amend] = true if options[:amend]
|
|
185
|
+
commit_options[:gpg_sign] = true if options[:sign]
|
|
186
|
+
return repo.commit(message, commit_options) unless options[:signoff]
|
|
187
|
+
|
|
188
|
+
arguments = ["--message=#{message}"]
|
|
189
|
+
arguments.push('--amend', '--no-edit') if options[:amend]
|
|
190
|
+
arguments << '--gpg-sign' if options[:sign]
|
|
191
|
+
arguments << '--signoff'
|
|
192
|
+
repo.lib.send(:command, 'commit', *arguments)
|
|
193
|
+
end
|
|
194
|
+
|
|
181
195
|
# Git add/rm, git commit, git push
|
|
182
196
|
def submit_changes(files, options)
|
|
183
197
|
message = options[:message]
|
|
@@ -190,8 +204,6 @@ module ModuleSync
|
|
|
190
204
|
end
|
|
191
205
|
end
|
|
192
206
|
begin
|
|
193
|
-
opts_commit = {}
|
|
194
|
-
opts_commit = { amend: true } if options[:amend]
|
|
195
207
|
if options[:pre_commit_script]
|
|
196
208
|
script = "#{File.dirname(__FILE__, 3)}/contrib/#{options[:pre_commit_script]}"
|
|
197
209
|
system(script, @directory)
|
|
@@ -200,7 +212,7 @@ module ModuleSync
|
|
|
200
212
|
puts "There were no changes in '#{@directory}'. Not committing."
|
|
201
213
|
return false unless @rebased
|
|
202
214
|
else
|
|
203
|
-
|
|
215
|
+
commit_changes(message, options)
|
|
204
216
|
end
|
|
205
217
|
if options[:remote_branch]
|
|
206
218
|
if @rebased || remote_branch_differ?(branch, options[:remote_branch])
|
data/lib/modulesync/version.rb
CHANGED
data/lib/modulesync.rb
CHANGED
|
@@ -151,8 +151,9 @@ module ModuleSync
|
|
|
151
151
|
pushed = puppet_module.repository.submit_changes(files_to_manage, options)
|
|
152
152
|
# Only bump/tag if pushing didn't fail (i.e. there were changes)
|
|
153
153
|
if pushed && options[:bump]
|
|
154
|
-
|
|
155
|
-
puppet_module.
|
|
154
|
+
signing_options = { sign: options[:sign], signoff: options[:signoff] }
|
|
155
|
+
new = puppet_module.bump(options[:message], options[:changelog], signing_options)
|
|
156
|
+
puppet_module.repository.tag(new, options[:tag_pattern], sign: options[:sign]) if options[:tag]
|
|
156
157
|
end
|
|
157
158
|
options[:pr] && (pushed || puppet_module.pull_request_branch_ready?) && puppet_module.open_pull_request
|
|
158
159
|
end
|
|
@@ -73,6 +73,50 @@ describe ModuleSync::Repository do
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
describe '#prepare_workspace' do
|
|
76
|
+
context 'with a fresh clone and an existing remote modulesync branch' do
|
|
77
|
+
before do
|
|
78
|
+
allow(Dir).to receive(:exist?).with('/tmp/example/.git').and_return(false)
|
|
79
|
+
allow(Git).to receive(:clone).with('https://github.com/example/repository.git', '/tmp/example').and_return(git)
|
|
80
|
+
allow(Git).to receive(:default_branch).with('https://github.com/example/repository.git').and_return('main')
|
|
81
|
+
allow(git).to receive(:current_branch).and_return('main', 'modulesync')
|
|
82
|
+
allow(branches).to receive(:local).and_return([])
|
|
83
|
+
allow(git).to receive(:checkout).with('origin/modulesync')
|
|
84
|
+
allow(git).to receive(:branch).with('modulesync').and_return(instance_double(Git::Branch, checkout: true))
|
|
85
|
+
allow(log).to receive(:between).with('modulesync', 'origin/main').and_return(log)
|
|
86
|
+
allow(log).to receive(:execute).and_return([instance_double(Git::Object::Commit)])
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'rebases and pushes the existing branch even when rendering makes no file changes' do
|
|
90
|
+
allow(git).to receive(:status).and_return(instance_double(Git::Status, added: {}, changed: {}, deleted: {}))
|
|
91
|
+
expect(git).to receive(:checkout).with('origin/modulesync').ordered
|
|
92
|
+
expect(git_lib).to receive(:send).with(:command, 'rebase', 'origin/main').ordered
|
|
93
|
+
expect(git_lib).to receive(:send).with(:command, 'push', '--force-with-lease', 'origin', 'modulesync').ordered
|
|
94
|
+
|
|
95
|
+
repository.prepare_workspace(branch: 'modulesync', operate_offline: false, rebase: true)
|
|
96
|
+
|
|
97
|
+
expect(repository.submit_changes([], branch: 'modulesync', message: 'Update', force: false)).to be true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it 'does not rebase unless requested' do
|
|
101
|
+
expect(Git).not_to receive(:default_branch)
|
|
102
|
+
expect(git_lib).not_to receive(:send)
|
|
103
|
+
|
|
104
|
+
repository.prepare_workspace(branch: 'modulesync', operate_offline: false)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'does not rebase an existing workspace in offline mode' do
|
|
109
|
+
allow(Dir).to receive(:exist?).with('/tmp/example/.git').and_return(true)
|
|
110
|
+
allow(git).to receive(:current_branch).and_return('modulesync')
|
|
111
|
+
expect(git).to receive(:reset_hard)
|
|
112
|
+
expect(git).not_to receive(:fetch)
|
|
113
|
+
expect(git).not_to receive(:pull)
|
|
114
|
+
expect(Git).not_to receive(:default_branch)
|
|
115
|
+
expect(git_lib).not_to receive(:send)
|
|
116
|
+
|
|
117
|
+
repository.prepare_workspace(branch: 'modulesync', operate_offline: true, rebase: true)
|
|
118
|
+
end
|
|
119
|
+
|
|
76
120
|
it 'fetches and rebases the selected branch onto the remote default branch when requested' do
|
|
77
121
|
allow(Dir).to receive(:exist?).with('/tmp/example/.git').and_return(true)
|
|
78
122
|
allow(Git).to receive(:default_branch).with('https://github.com/example/repository.git').and_return('main')
|
|
@@ -116,4 +160,35 @@ describe ModuleSync::Repository do
|
|
|
116
160
|
expect(result).to be true
|
|
117
161
|
end
|
|
118
162
|
end
|
|
163
|
+
|
|
164
|
+
describe '#commit_changes' do
|
|
165
|
+
it 'signs the commit when requested' do
|
|
166
|
+
expect(git).to receive(:commit).with('Update', { gpg_sign: true })
|
|
167
|
+
|
|
168
|
+
repository.commit_changes('Update', sign: true, signoff: false)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it 'uses the Git signoff option when requested' do
|
|
172
|
+
expect(git_lib).to receive(:send)
|
|
173
|
+
.with(:command, 'commit', '--message=Update', '--signoff')
|
|
174
|
+
|
|
175
|
+
repository.commit_changes('Update', sign: false, signoff: true)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it 'combines amend, signing, and signoff options' do
|
|
179
|
+
expect(git_lib).to receive(:send)
|
|
180
|
+
.with(:command, 'commit', '--message=Update', '--amend', '--no-edit', '--gpg-sign', '--signoff')
|
|
181
|
+
|
|
182
|
+
repository.commit_changes('Update', amend: true, sign: true, signoff: true)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
describe '#tag' do
|
|
187
|
+
it 'signs and pushes the tag when requested' do
|
|
188
|
+
expect(git).to receive(:add_tag).with('v1.2.3', sign: true)
|
|
189
|
+
expect(git).to receive(:push).with('origin', 'v1.2.3')
|
|
190
|
+
|
|
191
|
+
repository.tag('1.2.3', 'v%s', sign: true)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
119
194
|
end
|
|
@@ -70,5 +70,17 @@ describe ModuleSync do
|
|
|
70
70
|
|
|
71
71
|
described_class.manage_module(puppet_module, [], {})
|
|
72
72
|
end
|
|
73
|
+
|
|
74
|
+
it 'passes signing options to a release commit and tag' do
|
|
75
|
+
options = described_class.config_defaults.merge(message: 'Update', bump: true, tag: true, sign: true, signoff: true)
|
|
76
|
+
described_class.instance_variable_set(:@options, options)
|
|
77
|
+
allow(repository).to receive(:submit_changes).and_return(true)
|
|
78
|
+
expect(puppet_module).to receive(:bump)
|
|
79
|
+
.with('Update', nil, { sign: true, signoff: true })
|
|
80
|
+
.and_return('1.2.3')
|
|
81
|
+
expect(repository).to receive(:tag).with('1.2.3', '%s', sign: true)
|
|
82
|
+
|
|
83
|
+
described_class.manage_module(puppet_module, [], {})
|
|
84
|
+
end
|
|
73
85
|
end
|
|
74
86
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: modulesync
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vox Pupuli
|
|
@@ -266,7 +266,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
266
266
|
- !ruby/object:Gem::Version
|
|
267
267
|
version: '0'
|
|
268
268
|
requirements: []
|
|
269
|
-
rubygems_version: 4.0.
|
|
269
|
+
rubygems_version: 4.0.20
|
|
270
270
|
specification_version: 4
|
|
271
271
|
summary: Puppet Module Synchronizer
|
|
272
272
|
test_files: []
|