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)