diff --git a/README.rst b/README.rst index 010711ca9bf1a014ff498691a1da0427954628c3..6f8f638422a8d5e95adda02ea2af3de425001abc 100644 --- a/README.rst +++ b/README.rst @@ -450,6 +450,19 @@ boolean option:: repository = https://example.net/example.git/ ignore-ssl-certificate = true +Reproductible builds +~~~~~~~~~~~~~~~~~~~~ + +buildout's `allow-picked-versions` version can be set to false to prevent +buildout from picking the latest version of eggs. This options is usually set +to false in production deployments, to ensure that the buildout will be +reproductible because every dependencies have been pinned to a specific version. + +`slapos.recipe.build:gitclone` follows the same logic, when buildout does not +allow picked version, `slapos.recipe.build:gitclone` will not allow to clone +from a `branch`, but only from a fixed `revision`. + + Other options ~~~~~~~~~~~~~ diff --git a/slapos/recipe/build/tests.py b/slapos/recipe/build/tests.py index 9bccc087420e8bfd66acb33d31d6cb5b1657e600..2a8829ca27945577d8659cc3fd1fbec316491e09 100644 --- a/slapos/recipe/build/tests.py +++ b/slapos/recipe/build/tests.py @@ -52,6 +52,7 @@ class GitCloneNonInformativeTests(unittest.TestCase): 'buildout': { 'parts-directory': self.parts_directory_path, 'directory': self.dir, + 'allow-picked-versions': 'true', } } default_options = { @@ -111,6 +112,7 @@ class GitCloneNonInformativeTests(unittest.TestCase): 'buildout': { 'parts-directory': self.parts_directory_path, 'directory': self.dir, + 'allow-picked-versions': 'true', } } options = { @@ -136,6 +138,29 @@ class GitCloneNonInformativeTests(unittest.TestCase): def test_ignore_ssl_certificate_false(self): self.test_ignore_ssl_certificate(ignore_ssl_certificate=False) + def test_allow_picked_versions(self): + import slapos.recipe.gitclone + bo = { + 'buildout': { + 'parts-directory': self.parts_directory_path, + 'directory': self.dir, + 'allow-picked-versions': 'false', + } + } + with self.assertRaises(zc.buildout.UserError): + slapos.recipe.gitclone.Recipe( + bo, + 'test', + { 'repository': GIT_REPOSITORY, + 'branch': 'master' }) + # with a revision, no problem + recipe = slapos.recipe.gitclone.Recipe( + bo, + 'test', + { 'repository': GIT_REPOSITORY, + 'revision': REVISION }) + recipe.install() + def test_suite(): suite = unittest.TestSuite(( doctest.DocFileSuite( diff --git a/slapos/recipe/gitclone.py b/slapos/recipe/gitclone.py index 6c4d2b0b9852390927921556322878833549a72b..eb52500c5b7dc03a07868facaa8799eea0d1d502 100644 --- a/slapos/recipe/gitclone.py +++ b/slapos/recipe/gitclone.py @@ -164,6 +164,9 @@ class Recipe(object): if not os.path.exists(self.location): self.update = self.install + if not self.revision and not buildout['buildout']['allow-picked-versions'].lower() in TRUE_VALUES: + raise UserError('Revision must be specified when buildout runs with allow-picking-versions set to false') + def gitReset(self, revision=None): """Operates git reset on the repository.""" command = [self.git_command, 'reset', '--hard']