| |
@@ -0,0 +1,371 @@
|
| |
+ import mock
|
| |
+ import unittest
|
| |
+
|
| |
+ import logging
|
| |
+ import shutil
|
| |
+ import tempfile
|
| |
+
|
| |
+ from pprint import pprint
|
| |
+
|
| |
+ import koji
|
| |
+ import koji.daemon
|
| |
+
|
| |
+ from koji.daemon import SCM
|
| |
+
|
| |
+
|
| |
+ class TestSCM(unittest.TestCase):
|
| |
+
|
| |
+ def test_urlcheck(self):
|
| |
+ good = [
|
| |
+ "git://server/foo.git#bab0c73900241ef5c465d7e873e9d8b34c948e67",
|
| |
+ "git+ssh://server2/other/path#bab0c73900241ef5c465d7e873e9d8b34c948e67",
|
| |
+ "svn://server/path/to/code#bab0c73900241ef5c465d7e873e9d8b34c948e67",
|
| |
+ "svn+ssh://server/some/path#bab0c73900241ef5c465d7e873e9d8b34c948e67",
|
| |
+ "cvs://server/some/path#bab0c73900241ef5c465d7e873e9d8b34c948e67",
|
| |
+ "cvs+ssh://server/some/path#bab0c73900241ef5c465d7e873e9d8b34c948e67",
|
| |
+ ]
|
| |
+ bad = [
|
| |
+ "http://localhost/foo.html",
|
| |
+ "foo-1.1-1.src.rpm",
|
| |
+ "https://server/foo-1.1-1.src.rpm",
|
| |
+ ]
|
| |
+ for url in good:
|
| |
+ self.assertTrue(SCM.is_scm_url(url))
|
| |
+ for url in bad:
|
| |
+ self.assertFalse(SCM.is_scm_url(url))
|
| |
+
|
| |
+ @mock.patch('logging.getLogger')
|
| |
+ def test_init(self, getLogger):
|
| |
+ bad = [
|
| |
+ "git://user@@server/foo.git#bab0c73900241ef5c465d7e873e9d8b34c948e67",
|
| |
+ "git://user:pass@server/foo.git#bab0c73900241ef5c465d7e873e9d8b34c948e67",
|
| |
+ "git://server/foo.git;params=not_allowed",
|
| |
+ "git://server#asdasd", # no path
|
| |
+ "git://server/foo.git", # no fragment
|
| |
+ "http://localhost/foo.html",
|
| |
+ "git://@localhost/foo/?a=bar/",
|
| |
+ "http://localhost/foo.html?a=foo/",
|
| |
+ "foo-1.1-1.src.rpm",
|
| |
+ "git://",
|
| |
+ "https://server/foo-1.1-1.src.rpm",
|
| |
+ ]
|
| |
+ for url in bad:
|
| |
+ with self.assertRaises(koji.GenericError):
|
| |
+ scm = SCM(url)
|
| |
+
|
| |
+ url = "git://user@server/foo.git#bab0c73900241ef5c465d7e873e9d8b34c948e67"
|
| |
+ scm = SCM(url)
|
| |
+ self.assertEqual(scm.scheme, 'git://')
|
| |
+ self.assertEqual(scm.user, 'user')
|
| |
+ self.assertEqual(scm.host, 'server')
|
| |
+ self.assertEqual(scm.repository, '/foo.git')
|
| |
+ self.assertEqual(scm.module, '')
|
| |
+ self.assertEqual(scm.revision, 'bab0c73900241ef5c465d7e873e9d8b34c948e67')
|
| |
+ self.assertEqual(scm.use_common, True)
|
| |
+ self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
| |
+ self.assertEqual(scm.scmtype, 'GIT')
|
| |
+
|
| |
+ @mock.patch('logging.getLogger')
|
| |
+ def test_allowed(self, getLogger):
|
| |
+ config = '''
|
| |
+ goodserver:*:no
|
| |
+ !badserver:*
|
| |
+ !maybeserver:/badpath/*
|
| |
+ maybeserver:*:no
|
| |
+ '''
|
| |
+ good = [
|
| |
+ "git://goodserver/path1#1234",
|
| |
+ "git+ssh://maybeserver/path1#1234",
|
| |
+ ]
|
| |
+ bad = [
|
| |
+ "cvs://badserver/projects/42#ref",
|
| |
+ "svn://badserver/projects/42#ref",
|
| |
+ "git://maybeserver/badpath/project#1234",
|
| |
+ ]
|
| |
+ for url in good:
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ for url in bad:
|
| |
+ scm = SCM(url)
|
| |
+ try:
|
| |
+ scm.assert_allowed(config)
|
| |
+ except koji.BuildError:
|
| |
+ pass
|
| |
+ else:
|
| |
+ raise AssertionError("allowed bad url: %s" % url)
|
| |
+
|
| |
+ @mock.patch('logging.getLogger')
|
| |
+ def test_badrule(self, getLogger):
|
| |
+ config = '''
|
| |
+ bogus-entry-should-be-ignored
|
| |
+ goodserver:*:no
|
| |
+ !badserver:*
|
| |
+ '''
|
| |
+ url = "git://goodserver/path1#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+
|
| |
+ @mock.patch('logging.getLogger')
|
| |
+ def test_opts(self, getLogger):
|
| |
+ config = '''
|
| |
+ default:*
|
| |
+ nocommon:*:no
|
| |
+ srccmd:*:no:fedpkg,sources
|
| |
+ nosrc:*:no:
|
| |
+ mixed:/foo/*:no
|
| |
+ mixed:/bar/*:yes
|
| |
+ mixed:/baz/*:no:fedpkg,sources
|
| |
+ '''
|
| |
+
|
| |
+ url = "git://default/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, True)
|
| |
+ self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
| |
+
|
| |
+ url = "git://nocommon/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
| |
+
|
| |
+ url = "git://srccmd/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.assertEqual(scm.source_cmd, ['fedpkg', 'sources'])
|
| |
+
|
| |
+ url = "git://nosrc/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.assertEqual(scm.source_cmd, None)
|
| |
+
|
| |
+ url = "git://mixed/foo/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
| |
+
|
| |
+ url = "git://mixed/bar/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, True)
|
| |
+ self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
| |
+
|
| |
+ url = "git://mixed/baz/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.assertEqual(scm.source_cmd, ['fedpkg', 'sources'])
|
| |
+
|
| |
+ url = "git://mixed/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ with self.assertRaises(koji.BuildError):
|
| |
+ scm.assert_allowed(config)
|
| |
+
|
| |
+ url = "git://mixed/foo/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
| |
+
|
| |
+ url = "git://mixed/bar/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, True)
|
| |
+ self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
| |
+
|
| |
+ url = "git://mixed/baz/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(config)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.assertEqual(scm.source_cmd, ['fedpkg', 'sources'])
|
| |
+
|
| |
+ url = "git://mixed/koji.git#1234"
|
| |
+ scm = SCM(url)
|
| |
+ with self.assertRaises(koji.BuildError):
|
| |
+ scm.assert_allowed(config)
|
| |
+
|
| |
+
|
| |
+ class TestSCMCheckouts(unittest.TestCase):
|
| |
+
|
| |
+ def setUp(self):
|
| |
+ self.symlink = mock.patch('os.symlink').start()
|
| |
+ self.getLogger = mock.patch('logging.getLogger').start()
|
| |
+ self.log_output = mock.patch('koji.daemon.log_output').start()
|
| |
+ self.log_output.return_value = None
|
| |
+ self.tempdir = tempfile.mkdtemp()
|
| |
+ self.session = mock.MagicMock()
|
| |
+ self.uploadpath = mock.MagicMock()
|
| |
+ self.logfile = mock.MagicMock()
|
| |
+ self.config = '''
|
| |
+ default:*
|
| |
+ nocommon:*:no
|
| |
+ srccmd:*:no:fedpkg,sources
|
| |
+ nosrc:*:no:
|
| |
+ '''
|
| |
+
|
| |
+ def tearDown(self):
|
| |
+ mock.patch.stopall()
|
| |
+ shutil.rmtree(self.tempdir)
|
| |
+
|
| |
+ def test_checkout_git_nocommon(self):
|
| |
+
|
| |
+ url = "git://nocommon/koji.git#asdasd"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(self.config)
|
| |
+ scm.checkout(self.tempdir, session=self.session,
|
| |
+ uploadpath=self.uploadpath, logfile=self.logfile)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.symlink.assert_not_called()
|
| |
+ # expected commands
|
| |
+ cmd = ['git', 'clone', '-n', 'git://nocommon/koji.git',
|
| |
+ self.tempdir + '/koji']
|
| |
+ call1 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir, logerror=1,
|
| |
+ append=False, env=None)
|
| |
+ cmd = ['git', 'reset', '--hard', 'asdasd']
|
| |
+ call2 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir + '/koji',
|
| |
+ logerror=1, append=True, env=None)
|
| |
+ self.log_output.assert_has_calls([call1, call2])
|
| |
+
|
| |
+ def test_checkout_gitssh_nocommon(self):
|
| |
+
|
| |
+ url = "git+ssh://user@nocommon/koji.git#asdasd"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(self.config)
|
| |
+ scm.checkout(self.tempdir, session=self.session,
|
| |
+ uploadpath=self.uploadpath, logfile=self.logfile)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.symlink.assert_not_called()
|
| |
+ # expected commands
|
| |
+ cmd = ['git', 'clone', '-n', 'git+ssh://user@nocommon/koji.git',
|
| |
+ self.tempdir + '/koji']
|
| |
+ call1 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir, logerror=1,
|
| |
+ append=False, env=None)
|
| |
+ cmd = ['git', 'reset', '--hard', 'asdasd']
|
| |
+ call2 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir + '/koji',
|
| |
+ logerror=1, append=True, env=None)
|
| |
+ self.log_output.assert_has_calls([call1, call2])
|
| |
+
|
| |
+ def test_checkout_git_common(self):
|
| |
+
|
| |
+ url = "git://default/koji.git#asdasd"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(self.config)
|
| |
+ scm.checkout(self.tempdir, session=self.session,
|
| |
+ uploadpath=self.uploadpath, logfile=self.logfile)
|
| |
+ self.assertEqual(scm.use_common, True)
|
| |
+ self.symlink.assert_called_once()
|
| |
+ # expected commands
|
| |
+ cmd = ['git', 'clone', '-n', 'git://default/koji.git',
|
| |
+ self.tempdir + '/koji']
|
| |
+ call1 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir, logerror=1,
|
| |
+ append=False, env=None)
|
| |
+ cmd = ['git', 'reset', '--hard', 'asdasd']
|
| |
+ call2 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir + '/koji',
|
| |
+ logerror=1, append=True, env=None)
|
| |
+ cmd = ['git', 'clone', 'git://default/common.git', 'common']
|
| |
+ call3 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir,
|
| |
+ logerror=1, append=True, env=None)
|
| |
+ self.log_output.assert_has_calls([call1, call2, call3])
|
| |
+
|
| |
+ def test_checkout_error_in_command(self):
|
| |
+
|
| |
+ url = "git://nocommon/koji.git#asdasd"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(self.config)
|
| |
+ self.log_output.return_value = 1
|
| |
+ with self.assertRaises(koji.BuildError):
|
| |
+ scm.checkout(self.tempdir, session=self.session,
|
| |
+ uploadpath=self.uploadpath, logfile=self.logfile)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.symlink.assert_not_called()
|
| |
+ # expected commands
|
| |
+ cmd = ['git', 'clone', '-n', 'git://nocommon/koji.git',
|
| |
+ self.tempdir + '/koji']
|
| |
+ call1 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir, logerror=1,
|
| |
+ append=False, env=None)
|
| |
+ # should have errored after first command
|
| |
+ self.log_output.assert_has_calls([call1])
|
| |
+
|
| |
+ def test_checkout_cvs_common(self):
|
| |
+
|
| |
+ url = "cvs://default/cvsisdead?rpms/foo/EL3#sometag"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(self.config)
|
| |
+ scm.checkout(self.tempdir, session=self.session,
|
| |
+ uploadpath=self.uploadpath, logfile=self.logfile)
|
| |
+ self.assertEqual(scm.use_common, True)
|
| |
+ self.symlink.assert_called_once()
|
| |
+ # expected commands
|
| |
+ cmd = ['cvs', '-d', ':pserver:anonymous@default:/cvsisdead', 'checkout',
|
| |
+ '-r', 'sometag', 'rpms/foo/EL3']
|
| |
+ call1 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir, logerror=1,
|
| |
+ append=False, env=None)
|
| |
+ cmd = ['cvs', '-d', ':pserver:anonymous@default:/cvsisdead', 'checkout',
|
| |
+ 'common']
|
| |
+ call2 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir, logerror=1,
|
| |
+ append=True, env=None)
|
| |
+ self.log_output.assert_has_calls([call1, call2])
|
| |
+
|
| |
+ def test_checkout_cvs_ssh(self):
|
| |
+
|
| |
+ url = "cvs+ssh://user@nocommon/cvsisdead?rpms/foo/EL3#sometag"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(self.config)
|
| |
+ scm.checkout(self.tempdir, session=self.session,
|
| |
+ uploadpath=self.uploadpath, logfile=self.logfile)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.symlink.assert_not_called()
|
| |
+ # expected commands
|
| |
+ cmd = ['cvs', '-d', ':ext:user@nocommon:/cvsisdead', 'checkout', '-r',
|
| |
+ 'sometag', 'rpms/foo/EL3']
|
| |
+ call1 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir, logerror=1,
|
| |
+ append=False, env={'CVS_RSH': 'ssh'})
|
| |
+ self.log_output.assert_has_calls([call1])
|
| |
+
|
| |
+ def test_checkout_svn(self):
|
| |
+
|
| |
+ url = "svn://nocommon/dist?rpms/foo/EL3#revision"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(self.config)
|
| |
+ scm.checkout(self.tempdir, session=self.session,
|
| |
+ uploadpath=self.uploadpath, logfile=self.logfile)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.symlink.assert_not_called()
|
| |
+ # expected commands
|
| |
+ cmd = ['svn', 'checkout', '-r', 'revision',
|
| |
+ 'svn://nocommon/dist/rpms/foo/EL3', 'rpms/foo/EL3']
|
| |
+ call1 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir, logerror=1,
|
| |
+ append=False, env=None)
|
| |
+ self.log_output.assert_has_calls([call1])
|
| |
+
|
| |
+ def test_checkout_svn_ssh(self):
|
| |
+
|
| |
+ url = "svn+ssh://user@nocommon/dist?rpms/foo/EL3#revision"
|
| |
+ scm = SCM(url)
|
| |
+ scm.assert_allowed(self.config)
|
| |
+ scm.checkout(self.tempdir, session=self.session,
|
| |
+ uploadpath=self.uploadpath, logfile=self.logfile)
|
| |
+ self.assertEqual(scm.use_common, False)
|
| |
+ self.symlink.assert_not_called()
|
| |
+ # expected commands
|
| |
+ cmd = ['svn', 'checkout', '-r', 'revision',
|
| |
+ 'svn+ssh://user@nocommon/dist/rpms/foo/EL3', 'rpms/foo/EL3']
|
| |
+ call1 = mock.call(self.session, cmd[0], cmd, self.logfile,
|
| |
+ self.uploadpath, cwd=self.tempdir, logerror=1,
|
| |
+ append=False, env=None)
|
| |
+ self.log_output.assert_has_calls([call1])
|
| |
See the updated docstring for details. This change adds the ability to have entries like:
Which would explicitly block a host:repository pattern. This allows for somewhat more robust rules. In particular, it provides the option
to block specific subtrees of a host, but allow from it otherwise. E.g.