From d1fe6f57019d64edfe7d2aa51989fed1b162d238 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 12 2017 14:56:06 +0000 Subject: Add ways to customize the gitolite configuration file with snippets This commit adds two configuration key, GITOLITE_PRE_CONFIG and GITOLITE_POST_CONFIG allowing to point to files that will be included at the top or at the end of the gitolite configuration file. This allows customizing the gitolite configuration file with elements or information that are outside of pagure's control. This can be used in combination with the ``EXTERNAL_COMMITTER`` to give people of certain groups commit access to the git repositories. Signed-off-by: Pierre-Yves Chibon --- diff --git a/doc/configuration.rst b/doc/configuration.rst index ce15216..7e2b6c9 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -725,6 +725,37 @@ With this configuration (evaluated in the provided order): * only users in the ``contributor`` group will be allowed to be added to any project on this pagure instance. +GITOLITE_PRE_CONFIG +~~~~~~~~~~~~~~~~~~~ + +This configuration key allows you to include some content at the *top* of +the gitolite configuration file (such as some specific group definition), +thus allowing to customize the gitolite configuration file with elements +and information that are outside of pagure's control. + +This can be used in combination with ``GITOLITE_POST_CONFIG`` to further +customize gitolite's configuration file. It can also be used with +``EXTERNAL_COMMITTER`` to give commit access to git repos based on external +information. + +Defaults to: ``None`` + + +GITOLITE_POST_CONFIG +~~~~~~~~~~~~~~~~~~~ + +This configuration key allows you to include some content at the *end* of +the gitolite configuration file (such as some project definition or access), +thus allowing to customize the gitolite configuration file with elements +and information that are outside of pagure's control. + +This can be used in combination with ``GITOLITE_PRE_CONFIG`` to further +customize gitolite's configuration file. It can also be used with +``EXTERNAL_COMMITTER`` to give commit access to git repos based on external +information. + +Defaults to: ``None`` + Deprecated configuration keys ----------------------------- diff --git a/pagure/lib/git.py b/pagure/lib/git.py index c1f11aa..c50c27f 100644 --- a/pagure/lib/git.py +++ b/pagure/lib/git.py @@ -87,11 +87,35 @@ Subject: {subject} return patch -def write_gitolite_acls(session, configfile): +def __read_file(filename): + """ Reads the specified file and return its content. + Returns None if it could not read the file for any reason. + """ + if not os.path.exists(filename): + _log.info('Could not find file: %s', filename) + else: + with open(filename) as stream: + return stream.read() + + +def write_gitolite_acls(session, configfile, preconf=None, postconf=None): ''' Generate the configuration file for gitolite for all projects on the forge. ''' _log.info('Write down the gitolite configuration file') + + preconfig = None + if preconf: + _log.info( + 'Loading the file to include at the top of the generated one') + preconfig = __read_file(preconf) + + postconfig = None + if postconf: + _log.info( + 'Loading the file to include at the end of the generated one') + postconfig = __read_file(postconf) + global_pr_only = pagure.APP.config.get('PR_ONLY', False) config = [] groups = {} @@ -147,6 +171,9 @@ def write_gitolite_acls(session, configfile): config.append('') with open(configfile, 'w') as stream: + if preconfig: + stream.write(preconfig + '\n') + for key, users in groups.iteritems(): stream.write('@%s = %s\n' % (key, ' '.join(users))) stream.write('\n') @@ -154,6 +181,9 @@ def write_gitolite_acls(session, configfile): for row in config: stream.write(row + '\n') + if postconfig: + stream.write(postconfig + '\n') + def _get_gitolite_command(): """ Return the gitolite command to run based on the info in the @@ -191,7 +221,11 @@ def _generate_gitolite_acls(): """ _log.info('Refresh gitolite configuration') pagure.lib.git.write_gitolite_acls( - pagure.SESSION, pagure.APP.config['GITOLITE_CONFIG']) + pagure.SESSION, + pagure.APP.config['GITOLITE_CONFIG'], + preconf=pagure.APP.config.get('GITOLITE_PRE_CONFIG') or None, + postconf=pagure.APP.config.get('GITOLITE_POST_CONFIG') or None + ) cmd = _get_gitolite_command() if cmd: diff --git a/tests/test_pagure_lib_git.py b/tests/test_pagure_lib_git.py index d99fd5a..604cc7f 100644 --- a/tests/test_pagure_lib_git.py +++ b/tests/test_pagure_lib_git.py @@ -147,6 +147,226 @@ repo requests/forks/pingou/test3 os.unlink(outputconf) self.assertFalse(os.path.exists(outputconf)) + def test_write_gitolite_acls_preconf(self): + """ Test the write_gitolite_acls function of pagure.lib.git with + a preconf set """ + tests.create_projects(self.session) + + outputconf = os.path.join(self.path, 'test_gitolite.conf') + preconf = os.path.join(self.path, 'header_gitolite') + with open(preconf, 'w') as stream: + stream.write('# this is a header that is manually added') + + pagure.lib.git.write_gitolite_acls( + self.session, + outputconf, + preconf=preconf + ) + self.assertTrue(os.path.exists(outputconf)) + + with open(outputconf) as stream: + data = stream.read() + + exp = """# this is a header that is manually added + +repo test + R = @all + RW+ = pingou + +repo docs/test + R = @all + RW+ = pingou + +repo tickets/test + RW+ = pingou + +repo requests/test + RW+ = pingou + +repo test2 + R = @all + RW+ = pingou + +repo docs/test2 + R = @all + RW+ = pingou + +repo tickets/test2 + RW+ = pingou + +repo requests/test2 + RW+ = pingou + +repo somenamespace/test3 + R = @all + RW+ = pingou + +repo docs/somenamespace/test3 + R = @all + RW+ = pingou + +repo tickets/somenamespace/test3 + RW+ = pingou + +repo requests/somenamespace/test3 + RW+ = pingou + +""" + #print data + self.assertEqual(data, exp) + + os.unlink(outputconf) + self.assertFalse(os.path.exists(outputconf)) + + def test_write_gitolite_acls_preconf_postconf(self): + """ Test the write_gitolite_acls function of pagure.lib.git with + a postconf set """ + tests.create_projects(self.session) + + outputconf = os.path.join(self.path, 'test_gitolite.conf') + + preconf = os.path.join(self.path, 'header_gitolite') + with open(preconf, 'w') as stream: + stream.write('# this is a header that is manually added') + + postconf = os.path.join(self.path, 'footer_gitolite') + with open(postconf, 'w') as stream: + stream.write('# end of generated configuration') + + pagure.lib.git.write_gitolite_acls( + self.session, + outputconf, + preconf=preconf, + postconf=postconf + ) + self.assertTrue(os.path.exists(outputconf)) + + with open(outputconf) as stream: + data = stream.read() + + exp = """# this is a header that is manually added + +repo test + R = @all + RW+ = pingou + +repo docs/test + R = @all + RW+ = pingou + +repo tickets/test + RW+ = pingou + +repo requests/test + RW+ = pingou + +repo test2 + R = @all + RW+ = pingou + +repo docs/test2 + R = @all + RW+ = pingou + +repo tickets/test2 + RW+ = pingou + +repo requests/test2 + RW+ = pingou + +repo somenamespace/test3 + R = @all + RW+ = pingou + +repo docs/somenamespace/test3 + R = @all + RW+ = pingou + +repo tickets/somenamespace/test3 + RW+ = pingou + +repo requests/somenamespace/test3 + RW+ = pingou + +# end of generated configuration +""" + #print data + self.assertEqual(data, exp) + + os.unlink(outputconf) + self.assertFalse(os.path.exists(outputconf)) + + def test_write_gitolite_acls_postconf(self): + """ Test the write_gitolite_acls function of pagure.lib.git with + a preconf and a postconf set """ + tests.create_projects(self.session) + + outputconf = os.path.join(self.path, 'test_gitolite.conf') + postconf = os.path.join(self.path, 'footer_gitolite') + with open(postconf, 'w') as stream: + stream.write('# end of generated configuration') + + pagure.lib.git.write_gitolite_acls( + self.session, + outputconf, + postconf=postconf + ) + self.assertTrue(os.path.exists(outputconf)) + + with open(outputconf) as stream: + data = stream.read() + + exp = """ +repo test + R = @all + RW+ = pingou + +repo docs/test + R = @all + RW+ = pingou + +repo tickets/test + RW+ = pingou + +repo requests/test + RW+ = pingou + +repo test2 + R = @all + RW+ = pingou + +repo docs/test2 + R = @all + RW+ = pingou + +repo tickets/test2 + RW+ = pingou + +repo requests/test2 + RW+ = pingou + +repo somenamespace/test3 + R = @all + RW+ = pingou + +repo docs/somenamespace/test3 + R = @all + RW+ = pingou + +repo tickets/somenamespace/test3 + RW+ = pingou + +repo requests/somenamespace/test3 + RW+ = pingou + +# end of generated configuration +""" + #print data + self.assertEqual(data, exp) + + os.unlink(outputconf) + self.assertFalse(os.path.exists(outputconf)) + def test_write_gitolite_acls_deploykeys(self): """ Test write_gitolite_acls function to add deploy keys. """ tests.create_projects(self.session)