From 75a89dd03815f11d782a7298934f75a4a975dae9 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Apr 25 2018 09:06:03 +0000 Subject: [PATCH 1/2] Add support for repository templates for sources and forks Signed-off-by: Pierre-Yves Chibon --- diff --git a/doc/configuration.rst b/doc/configuration.rst index 12654e3..8f8a354 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -576,6 +576,28 @@ Defaults to: ``['issue_comment', 'issue_create', 'issue_change_status', 'pull_re Optional options ---------------- +Git repository templates +~~~~~~~~~~~~~~~~~~~~~~~~ + +PROJECT_TEMPLATE_PATH +^^^^^^^^^^^^^^^^^^^^^ + +This configuration key allows you to specify the path to a git repository +to use as a template when creating new repository for new projects. +This template will not be used for forks nor any of the git repository but +the one used for the sources (ie: it will not be used for the tickets, +requests or docs repositories). + +FORK_TEMPLATE_PATH +^^^^^^^^^^^^^^^^^^ + +This configuration key allows you to specify the path to a git repository +to use as a template when creating new repository for new forks. +This template will not be used for any of the git repository but +the one used for the sources of forks (ie: it will not be used for the +tickets, requests or docs repositories). + + SSH_KEYS ~~~~~~~~ @@ -595,6 +617,7 @@ Where `` and `` must be replaced by your values. ITEM_PER_PAGE ~~~~~~~~~~~~~ + This configuration key allows you to configure the length of a page by setting the number of items on the page. Items can be commits, users, groups, or projects for example. diff --git a/pagure/lib/tasks.py b/pagure/lib/tasks.py index 3e2d6fc..727e80b 100644 --- a/pagure/lib/tasks.py +++ b/pagure/lib/tasks.py @@ -269,13 +269,30 @@ def create_project(self, session, username, namespace, name, add_readme, gitrepo = os.path.join(pagure_config['GIT_FOLDER'], project.path) # Add the readme file if it was asked - if not add_readme: - _log.debug('Create git repo at: %s', gitrepo) - pygit2.init_repository(gitrepo, bare=True) + _log.debug('Create git repo at: %s', gitrepo) + templ = None + if project.is_fork: + templ = pagure_config.get('FORK_TEMPLATE_PATH') else: + templ = pagure_config.get('PROJECT_TEMPLATE_PATH') + if templ: + if not os.path.exists(templ): + _log.warning( + 'Invalid git template configured: %s, not found on disk', + templ) + templ = None + else: + _log.debug(' Using template at: %s', templ) + + pygit2.init_repository( + gitrepo, bare=True, template_path=templ) + if add_readme: + # Clone main project temp_gitrepo_path = tempfile.mkdtemp(prefix='pagure-') - temp_gitrepo = pygit2.init_repository(temp_gitrepo_path, - bare=False) + temp_gitrepo = pygit2.clone_repository( + gitrepo, temp_gitrepo_path, bare=False) + + # Add README file author = userobj.fullname or userobj.user author_email = userobj.default_email if six.PY2: @@ -291,7 +308,15 @@ def create_project(self, session, username, namespace, name, add_readme, tree = temp_gitrepo.index.write_tree() temp_gitrepo.create_commit( 'HEAD', author, author, 'Added the README', tree, []) - pygit2.clone_repository(temp_gitrepo_path, gitrepo, bare=True) + + # Push the README back to the main project + ori_remote = temp_gitrepo.remotes[0] + master_ref = temp_gitrepo.lookup_reference('HEAD').resolve() + refname = '%s:%s' % (master_ref.name, master_ref.name) + + _log.info('Pushing to %s: %s', ori_remote.name, refname) + pagure.lib.repo.PagureRepo.push(ori_remote, refname) + shutil.rmtree(temp_gitrepo_path) # Make the repo exportable via apache From 8a428c30b31afb40c8d27d4fc585ceae6a6ee7a0 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Apr 25 2018 09:06:08 +0000 Subject: [PATCH 2/2] Add a test for creating a git repository with a template Signed-off-by: Pierre-Yves Chibon --- diff --git a/tests/test_pagure_flask_ui_app.py b/tests/test_pagure_flask_ui_app.py index 8f712d8..73a3e86 100644 --- a/tests/test_pagure_flask_ui_app.py +++ b/tests/test_pagure_flask_ui_app.py @@ -512,6 +512,84 @@ class PagureFlaskApptests(tests.Modeltests): self.assertTrue(os.path.exists( os.path.join(self.path, 'repos', 'requests', '%s.git' % project))) + @patch('pygit2.init_repository', wraps=pygit2.init_repository) + def test_new_project_with_template(self, pygit2init): + """ Test the new_project endpoint for a new project with a template set. + """ + # Before + projects = pagure.lib.search_projects(self.session) + self.assertEqual(len(projects), 0) + self.assertFalse(os.path.exists( + os.path.join(self.path, 'repos', 'project-1.git'))) + self.assertFalse(os.path.exists( + os.path.join(self.path, 'repos', 'tickets', 'project-1.git'))) + self.assertFalse(os.path.exists( + os.path.join(self.path, 'repos', 'docs', 'project-1.git'))) + self.assertFalse(os.path.exists( + os.path.join(self.path, 'repos', 'requests', 'project-1.git'))) + + user = tests.FakeUser() + user.username = 'foo' + with tests.user_set(self.app.application, user): + output = self.app.get('/new/') + self.assertEqual(output.status_code, 200) + self.assertIn( + b'Create new Project', output.data) + + csrf_token = self.get_csrf(output=output) + + data = { + 'description': 'test', + 'name': 'project-1', + 'csrf_token': csrf_token, + 'create_readme': True, + } + output = self.app.post('/new/', data=data, follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\ntest
', + output.data if six.PY2 else output.data.decode('utf-8')) + + self.assertEqual(pygit2init.call_count, 4) + pygit2init.assert_any_call( + u'%s/repos/project-1.git' % self.path, + bare=True, template_path=None) + + path = os.path.join(self.path, 'repos', 'project-1.git') + with patch.dict( + 'pagure.config.config', + {'PROJECT_TEMPLATE_PATH': path}): + data = { + 'description': 'test2', + 'name': 'project-2', + 'csrf_token': csrf_token, + 'create_readme': True, + } + output = self.app.post('/new/', data=data, follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\ntest2
', + output.data if six.PY2 else output.data.decode('utf-8')) + + self.assertEqual(pygit2init.call_count, 8) + pygit2init.assert_any_call( + u'%s/repos/project-2.git' % self.path, + bare=True, + template_path=u'%s/repos/project-1.git' % self.path) + + # After + projects = pagure.lib.search_projects(self.session) + self.assertEqual(len(projects), 2) + for project in ['project-1', 'project-2']: + self.assertTrue(os.path.exists( + os.path.join(self.path, 'repos', '%s.git' % project))) + self.assertTrue(os.path.exists( + os.path.join(self.path, 'repos', 'tickets', '%s.git' % project))) + self.assertTrue(os.path.exists( + os.path.join(self.path, 'repos', 'docs', '%s.git' % project))) + self.assertTrue(os.path.exists( + os.path.join(self.path, 'repos', 'requests', '%s.git' % project))) + @patch('pagure.ui.app.admin_session_timedout') def test_user_settings(self, ast): """ Test the user_settings endpoint. """