diff --git a/openstack_releases/cmds/validate.py b/openstack_releases/cmds/validate.py index c44a20ff91..e32f5a81c4 100644 --- a/openstack_releases/cmds/validate.py +++ b/openstack_releases/cmds/validate.py @@ -668,12 +668,13 @@ def validate_existing_tags(deliv, context): ) if actual_sha != project.hash: context.error( - ('Version %s in %s is on ' - 'commit %s instead of %s') % - (release.version, - project.repo.name, - actual_sha, - project.hash)) + 'Version {} in {} is on ' + 'commit {!r} instead of {!r}'.format( + release.version, + project.repo.name, + actual_sha, + project.hash) + ) else: print('{} tag exists and is correct for {}'.format( release.version, project.repo.name)) diff --git a/openstack_releases/tests/test_validate.py b/openstack_releases/tests/test_validate.py index 288ce852a3..4df3727dbd 100644 --- a/openstack_releases/tests/test_validate.py +++ b/openstack_releases/tests/test_validate.py @@ -16,6 +16,7 @@ from __future__ import unicode_literals import logging import os +import re import textwrap import fixtures @@ -30,6 +31,70 @@ from openstack_releases import processutils from openstack_releases import yamlutils +class GPGKeyFixture(fixtures.Fixture): + """Creates a GPG key for testing. + + It's recommended that this be used in concert with a unique home + directory. + """ + + def setUp(self): + super(GPGKeyFixture, self).setUp() + # Force a temporary home directory with a short path so the + # gpg commands do not complain about an excessively long + # value. + self.useFixture(fixtures.TempHomeDir('/tmp')) + tempdir = self.useFixture(fixtures.TempDir('/tmp')) + gnupg_version_re = re.compile('^gpg\s.*\s([\d+])\.([\d+])\.([\d+])') + gnupg_version = processutils.check_output( + ['gpg', '--version'], + cwd=tempdir.path).decode('utf-8') + for line in gnupg_version.split('\n'): + gnupg_version = gnupg_version_re.match(line) + if gnupg_version: + gnupg_version = (int(gnupg_version.group(1)), + int(gnupg_version.group(2)), + int(gnupg_version.group(3))) + break + else: + if gnupg_version is None: + gnupg_version = (0, 0, 0) + + config_file = tempdir.path + '/key-config' + with open(config_file, 'wt') as f: + if gnupg_version[0] == 2 and gnupg_version[1] >= 1: + f.write(textwrap.dedent(""" + %no-protection + %transient-key + """)) + f.write(textwrap.dedent(""" + %no-ask-passphrase + Key-Type: RSA + Name-Real: Example Key + Name-Comment: N/A + Name-Email: example@example.com + Expire-Date: 2d + %commit + """)) + + # Note that --quick-random (--debug-quick-random in GnuPG 2.x) + # does not have a corresponding preferences file setting and + # must be passed explicitly on the command line instead + if gnupg_version[0] == 1: + gnupg_random = '--quick-random' + elif gnupg_version[0] >= 2: + gnupg_random = '--debug-quick-random' + else: + gnupg_random = '' + + cmd = ['gpg', '--gen-key', '--batch'] + if gnupg_random: + cmd.append(gnupg_random) + cmd.append('key-config') + + processutils.check_call(cmd, cwd=tempdir.path) + + class GitRepoFixture(fixtures.Fixture): logger = logging.getLogger('git') @@ -42,10 +107,13 @@ class GitRepoFixture(fixtures.Fixture): def setUp(self): super().setUp() + self.useFixture(GPGKeyFixture()) os.makedirs(self.path) self.git('init', '.') self.git('config', '--local', 'user.email', 'example@example.com') self.git('config', '--local', 'user.name', 'super developer') + self.git('config', '--local', 'user.signingkey', + 'example@example.com') def git(self, *args): self.logger.debug('$ git %s', ' '.join(args)) @@ -59,14 +127,17 @@ class GitRepoFixture(fixtures.Fixture): def commit(self, message='commit message'): self.git('add', '.') self.git('commit', '-m', message) - sha = self.git('show', '--pretty=format:%H') - return sha.decode('utf-8') + sha = self.git('log', '-n', '1', '--pretty=format:%H') + return sha.decode('utf-8').strip() def add_file(self, name): with open(os.path.join(self.path, name), 'w') as f: f.write('adding %s\n' % name) return self.commit('add %s' % name) + def tag(self, version): + self.git('tag', '-s', '-m', version, version) + class TestDecorators(base.BaseTestCase): @@ -675,9 +746,18 @@ class TestValidateExistingTags(base.BaseTestCase): def setUp(self): super().setUp() self.ctx = validate.ValidationContext() - gitutils.clone_repo(self.ctx.workdir, 'openstack/release-test') + self._make_repo() - def test_valid(self): + def _make_repo(self): + self.repo = self.useFixture( + GitRepoFixture(self.ctx.workdir, 'openstack/release-test') + ) + self.commit_1 = self.repo.add_file('testfile1.txt') + self.repo.tag('0.8.0') + self.commit_2 = self.repo.add_file('testfile2.txt') + + @mock.patch('openstack_releases.gitutils.safe_clone_repo') + def test_valid(self, clone): deliv = deliverable.Deliverable( team='team', series='ocata', @@ -688,7 +768,7 @@ class TestValidateExistingTags(base.BaseTestCase): {'version': '0.8.0', 'projects': [ {'repo': 'openstack/release-test', - 'hash': 'a26e6a2e8a5e321b2e3517dbb01a7b9a56a8bfd5', + 'hash': self.commit_1, 'tarball-base': 'openstack-release-test'}, ]} ], @@ -710,8 +790,7 @@ class TestValidateExistingTags(base.BaseTestCase): {'version': '0.8.0', 'projects': [ {'repo': 'openstack/release-test', - # hash from the previous release - 'hash': '88af0f601895d54fb0a45b796cdd045a2b3636a3'}, + 'hash': self.commit_2}, ]} ], },