From 5bc60d0963088bac6ba3cc573e6fad99060764a5 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Sun, 9 Apr 2023 15:12:06 -0700 Subject: [PATCH] vcsrepo: add mode option Signed-off-by: Robin H. Johnson Reference: https://github.com/puppetlabs/puppetlabs-vcsrepo/issues/598 --- CHANGELOG.md | 6 ++++++ README.md | 12 ++++++------ REFERENCE.md | 4 ++++ lib/puppet/provider/vcsrepo.rb | 14 +++++++++++--- lib/puppet/provider/vcsrepo/bzr.rb | 2 +- lib/puppet/provider/vcsrepo/cvs.rb | 2 +- lib/puppet/provider/vcsrepo/git.rb | 21 ++++++++++++--------- lib/puppet/provider/vcsrepo/hg.rb | 2 +- lib/puppet/provider/vcsrepo/p4.rb | 2 +- lib/puppet/provider/vcsrepo/svn.rb | 2 +- lib/puppet/type/vcsrepo.rb | 4 ++++ spec/acceptance/clone_repo_spec.rb | 21 +++++++++++++++++++++ 12 files changed, 69 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7db42649..f59e22c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org). +## UNRELEASED + +### Added + +- support for directory modes for repos [\#599](https://github.com/puppetlabs/puppetlabs-vcsrepo/issues/599) ([robbat2](https://github.com/robbat2)) + ## [v5.4.0](https://github.com/puppetlabs/puppetlabs-vcsrepo/tree/v5.4.0) (2023-01-31) [Full Changelog](https://github.com/puppetlabs/puppetlabs-vcsrepo/compare/v5.3.0...v5.4.0) diff --git a/README.md b/README.md index ad38e235..fdc28790 100644 --- a/README.md +++ b/README.md @@ -785,37 +785,37 @@ For information on the classes and types, see the [REFERENCE.md](https://github. Features: `bare_repositories`, `depth`, `multiple_remotes`, `reference_tracking`, `ssh_identity`, `submodules`, `user` -Parameters: `depth`, `ensure`, `excludes`, `force`, `group`, `identity`, `owner`, `path`, `provider`, `remote`, `revision`, `source`, `user` +Parameters: `depth`, `ensure`, `excludes`, `force`, `group`, `identity`, `owner`, `path`, `provider`, `remote`, `revision`, `source`, `user`, `mode` ##### `bzr` - Supports the Bazaar VCS. Features: `reference_tracking` -Parameters: `ensure`, `excludes`, `force`, `group`, `owner`, `path`, `provider`, `revision`, `source` +Parameters: `ensure`, `excludes`, `force`, `group`, `owner`, `path`, `provider`, `revision`, `source`, `mode` ##### `cvs` - Supports the CVS VCS. Features: `cvs_rsh`, `gzip_compression`, `modules`, `reference_tracking`, `user` -Parameters: `compression`, `cvs_rsh`, `ensure`, `excludes`, `force`, `group`, `module`, `owner`, `path`, `provider` +Parameters: `compression`, `cvs_rsh`, `ensure`, `excludes`, `force`, `group`, `module`, `owner`, `path`, `provider`, `mode` ##### `hg` - Supports the Mercurial VCS. Features: `reference_tracking`, `ssh_identity`, `user` -Parameters: `ensure`, `excludes`, `force`, `group`, `identity`, `owner`, `path`, `provider`, `revision`, `source`, `user` +Parameters: `ensure`, `excludes`, `force`, `group`, `identity`, `owner`, `path`, `provider`, `revision`, `source`, `user`, `mode` ##### `p4` - Supports the Perforce VCS. Features: `p4config`, `reference_tracking` -Parameters: `ensure`, `excludes`, `force`, `group`, `owner`, `p4config`, `path`, `provider`, `revision`, `source` +Parameters: `ensure`, `excludes`, `force`, `group`, `owner`, `p4config`, `path`, `provider`, `revision`, `source`, `mode` ##### `svn` - Supports the Subversion VCS. Features: `basic_auth`, `configuration`, `conflict`, `depth`, `filesystem_types`, `reference_tracking` -Parameters: `basic_auth_password`, `basic_auth_username`, `configuration`, `conflict`, `ensure`, `excludes`, `force`, `fstype`, `group`, `includes`, `owner`, `path`, `provider`, `revision`, `source`, `trust_server_cert` +Parameters: `basic_auth_password`, `basic_auth_username`, `configuration`, `conflict`, `ensure`, `excludes`, `force`, `fstype`, `group`, `includes`, `owner`, `path`, `provider`, `revision`, `source`, `trust_server_cert`, `mode` #### Features diff --git a/REFERENCE.md b/REFERENCE.md index d3486f91..563d3e10 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -77,6 +77,7 @@ The following parameters are available in the `vcsrepo` type. * [`trust_server_cert`](#-vcsrepo--trust_server_cert) * [`umask`](#-vcsrepo--umask) * [`user`](#-vcsrepo--user) +* [`mode`](#-vcsrepo--mode) ##### `basic_auth_password` @@ -203,3 +204,6 @@ Sets the umask to be used for all repo operations The user to run for repository operations +##### `mode` + +Sets the mode for the repository directory (non-recursive). diff --git a/lib/puppet/provider/vcsrepo.rb b/lib/puppet/provider/vcsrepo.rb index ca5963f7..db88213c 100644 --- a/lib/puppet/provider/vcsrepo.rb +++ b/lib/puppet/provider/vcsrepo.rb @@ -15,18 +15,26 @@ def check_force private - def set_ownership + def set_ownership_and_permissions owner = @resource.value(:owner) || nil group = @resource.value(:group) || nil + mode = @resource.value(:mode) || nil excludes = @resource.value(:excludes) || nil + # Change the permission on the repo itself. + # The VCS should maintain permissions on files within the checkout. + FileUtils.chmod(mode, @resource.value(:path)) unless mode.nil? + # We might have no work to do, and this makes it easier for the callers. + return if owner.nil? && group.nil? + if excludes.nil? || excludes.empty? - FileUtils.chown_R(owner, group, @resource.value(:path)) + FileUtils.chown_R(owner, group, @resource.value(:path)) unless owner.nil? && group.nil? else - FileUtils.chown(owner, group, files) + FileUtils.chown(owner, group, files) unless owner.nil? && group.nil? end end def files + # Expensive on large repos excludes = @resource.value(:excludes) path = @resource.value(:path) Dir["#{path}/**/*"].reject { |f| excludes.any? { |p| f.start_with?("#{path}/#{p}") } } diff --git a/lib/puppet/provider/vcsrepo/bzr.rb b/lib/puppet/provider/vcsrepo/bzr.rb index 30ac813e..95b84908 100644 --- a/lib/puppet/provider/vcsrepo/bzr.rb +++ b/lib/puppet/provider/vcsrepo/bzr.rb @@ -103,6 +103,6 @@ def clone_repository(revision) end def update_owner - set_ownership if @resource.value(:owner) || @resource.value(:group) + set_ownership_and_permissions if @resource.value(:owner) || @resource.value(:group) || @resource.value(:mode) end end diff --git a/lib/puppet/provider/vcsrepo/cvs.rb b/lib/puppet/provider/vcsrepo/cvs.rb index 651dc78a..2bc8c226 100644 --- a/lib/puppet/provider/vcsrepo/cvs.rb +++ b/lib/puppet/provider/vcsrepo/cvs.rb @@ -136,7 +136,7 @@ def create_repository(path) end def update_owner - set_ownership if @resource.value(:owner) || @resource.value(:group) + set_ownership_and_permissions if @resource.value(:owner) || @resource.value(:group) || @resource.value(:mode) end def runcvs(*args) diff --git a/lib/puppet/provider/vcsrepo/git.rb b/lib/puppet/provider/vcsrepo/git.rb index e7400254..79f70808 100644 --- a/lib/puppet/provider/vcsrepo/git.rb +++ b/lib/puppet/provider/vcsrepo/git.rb @@ -39,7 +39,7 @@ def create end end - update_owner_and_excludes + update_owner_permission_and_excludes end def destroy @@ -101,7 +101,7 @@ def revision=(desired) if !ensure_bare_or_mirror? && @resource.value(:submodules) == :true update_submodules end - update_owner_and_excludes + update_owner_permission_and_excludes end def bare_exists? @@ -239,7 +239,7 @@ def update_references at_path do git_remote_action('fetch', @resource.value(:remote)) git_remote_action(*fetch_tags_args, @resource.value(:remote)) - update_owner_and_excludes + update_owner_permission_and_excludes end end @@ -256,6 +256,8 @@ def convert_working_copy_to_bare FileUtils.mv(File.join(@resource.value(:path), '.git'), tempdir) FileUtils.rm_rf(@resource.value(:path)) FileUtils.mv(tempdir, @resource.value(:path)) + FileUtils.chown(@resource.value(:user), @resource.value(:group), @resource.value(:path)) if @resource.value(:user) || @resource.value(:group) + FileUtils.chmod(@resource.value(:mode), @resource.value(:path)) if @resource.value(:mode) at_path do exec_git('config', '--local', '--bool', 'core.bare', 'true') return unless @resource.value(:ensure) == :mirror @@ -275,13 +277,15 @@ def convert_bare_to_working_copy notice 'Converting bare repository to working copy repository' FileUtils.mv(@resource.value(:path), tempdir) FileUtils.mkdir(@resource.value(:path)) + FileUtils.chown(@resource.value(:user), @resource.value(:group), @resource.value(:path)) if @resource.value(:user) || @resource.value(:group) + FileUtils.chmod(@resource.value(:mode), @resource.value(:path)) if @resource.value(:mode) FileUtils.mv(tempdir, File.join(@resource.value(:path), '.git')) if commits? at_path do exec_git('config', '--local', '--bool', 'core.bare', 'false') reset('HEAD') git_with_identity('checkout', '--force') - update_owner_and_excludes + update_owner_permission_and_excludes end end set_no_mirror if mirror? @@ -415,7 +419,8 @@ def init_repository else # normal init FileUtils.mkdir(@resource.value(:path)) - FileUtils.chown(@resource.value(:user), nil, @resource.value(:path)) if @resource.value(:user) + FileUtils.chown(@resource.value(:user), @resource.value(:group), @resource.value(:path)) if @resource.value(:user) || @resource.value(:group) + FileUtils.chmod(@resource.value(:mode), @resource.value(:path)) if @resource.value(:mode) args = ['init'] if @resource.value(:ensure) == :bare args << '--bare' @@ -598,10 +603,8 @@ def get_revision(rev = 'HEAD') end # @!visibility private - def update_owner_and_excludes - if @resource.value(:owner) || @resource.value(:group) - set_ownership - end + def update_owner_permission_and_excludes + set_ownership_and_permissions if @resource.value(:owner) || @resource.value(:group) || @resource.value(:mode) set_excludes if @resource.value(:excludes) end diff --git a/lib/puppet/provider/vcsrepo/hg.rb b/lib/puppet/provider/vcsrepo/hg.rb index e626d988..6f485b7c 100644 --- a/lib/puppet/provider/vcsrepo/hg.rb +++ b/lib/puppet/provider/vcsrepo/hg.rb @@ -116,7 +116,7 @@ def clone_repository(revision) end def update_owner - set_ownership if @resource.value(:owner) || @resource.value(:group) + set_ownership_and_permissions if @resource.value(:owner) || @resource.value(:group) || @resource.value(:mode) end def sensitive? diff --git a/lib/puppet/provider/vcsrepo/p4.rb b/lib/puppet/provider/vcsrepo/p4.rb index 8b213a16..60249fb4 100644 --- a/lib/puppet/provider/vcsrepo/p4.rb +++ b/lib/puppet/provider/vcsrepo/p4.rb @@ -101,7 +101,7 @@ def source=(_desired) private def update_owner - set_ownership if @resource.value(:owner) || @resource.value(:group) + set_ownership_and_permissions if @resource.value(:owner) || @resource.value(:group) || @resource.value(:mode) end # Sync the client workspace files to head or specified revision. diff --git a/lib/puppet/provider/vcsrepo/svn.rb b/lib/puppet/provider/vcsrepo/svn.rb index c0d985ec..47700f0a 100644 --- a/lib/puppet/provider/vcsrepo/svn.rb +++ b/lib/puppet/provider/vcsrepo/svn.rb @@ -265,7 +265,7 @@ def create_repository(path) end def update_owner - set_ownership if @resource.value(:owner) || @resource.value(:group) + set_ownership_and_permissions if @resource.value(:owner) || @resource.value(:group) || @resource.value(:mode) end def update_includes(paths) diff --git a/lib/puppet/type/vcsrepo.rb b/lib/puppet/type/vcsrepo.rb index e06bf6a7..35bf828b 100644 --- a/lib/puppet/type/vcsrepo.rb +++ b/lib/puppet/type/vcsrepo.rb @@ -215,6 +215,10 @@ def insync?(is) desc 'The group/gid that owns the repository files' end + newparam :mode do + desc 'The permission for the repository directory itself (not recursive)' + end + newparam :user do desc 'The user to run for repository operations' end diff --git a/spec/acceptance/clone_repo_spec.rb b/spec/acceptance/clone_repo_spec.rb index 48e04b6a..5ce4fb96 100644 --- a/spec/acceptance/clone_repo_spec.rb +++ b/spec/acceptance/clone_repo_spec.rb @@ -624,4 +624,25 @@ it { is_expected.to be_mode '664' } end end + + context 'with mode' do + pp = <<-MANIFEST + vcsrepo { "#{tmpdir}/testrepo_mode": + ensure => present, + provider => git, + source => "file://#{tmpdir}/testrepo.git", + mode => 'u=rwX,g=rX,o=X', + } + MANIFEST + it 'clones a repo' do + # Run it twice and test for idempotency + idempotent_apply(pp) + end + + describe file("#{tmpdir}/testrepo_mode") do + # NOTE: '0664' is not supported by 'be_mode'; this must be three digits + # unless the first octet is non-zero. + it { is_expected.to be_mode '751' } + end + end end