1152 lines
37 KiB
Python
1152 lines
37 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
import itertools
|
|
import logging
|
|
import os.path
|
|
import re
|
|
import subprocess
|
|
import textwrap
|
|
|
|
import fixtures
|
|
import mock
|
|
from testtools.content import text_content
|
|
|
|
from reno import config
|
|
from reno import create
|
|
from reno import scanner
|
|
from reno.tests import base
|
|
from reno import utils
|
|
|
|
|
|
_SETUP_TEMPLATE = """
|
|
import setuptools
|
|
try:
|
|
import multiprocessing # noqa
|
|
except ImportError:
|
|
pass
|
|
|
|
setuptools.setup(
|
|
setup_requires=['pbr'],
|
|
pbr=True)
|
|
"""
|
|
|
|
_CFG_TEMPLATE = """
|
|
[metadata]
|
|
name = testpkg
|
|
summary = Test Package
|
|
|
|
[files]
|
|
packages =
|
|
testpkg
|
|
"""
|
|
|
|
|
|
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()
|
|
tempdir = self.useFixture(fixtures.TempDir())
|
|
gnupg_version_re = re.compile('^gpg\s.*\s([\d+])\.([\d+])\.([\d+])')
|
|
gnupg_version = utils.check_output(['gpg', '--version'],
|
|
cwd=tempdir.path)
|
|
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'
|
|
f = open(config_file, 'wt')
|
|
try:
|
|
if gnupg_version[0] == 2 and gnupg_version[1] >= 1:
|
|
f.write("""
|
|
%no-protection
|
|
%transient-key
|
|
""")
|
|
f.write("""
|
|
%no-ask-passphrase
|
|
Key-Type: RSA
|
|
Name-Real: Example Key
|
|
Name-Comment: N/A
|
|
Name-Email: example@example.com
|
|
Expire-Date: 2d
|
|
Preferences: (setpref)
|
|
%commit
|
|
""")
|
|
finally:
|
|
f.close()
|
|
# 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(config_file)
|
|
subprocess.check_call(
|
|
cmd,
|
|
cwd=tempdir.path,
|
|
# Direct stderr to its own pipe, from which we don't read,
|
|
# to quiet the commands.
|
|
stderr=subprocess.PIPE,
|
|
)
|
|
|
|
|
|
class Base(base.TestCase):
|
|
|
|
logger = logging.getLogger('test')
|
|
|
|
def _run_git(self, *args):
|
|
self.logger.debug('$ git %s', ' '.join(args))
|
|
output = utils.check_output(
|
|
['git'] + list(args),
|
|
cwd=self.reporoot,
|
|
)
|
|
self.logger.debug(output)
|
|
return output
|
|
|
|
def _git_setup(self):
|
|
os.makedirs(self.reporoot)
|
|
self._run_git('init', '.')
|
|
self._run_git('config', '--local', 'user.email', 'example@example.com')
|
|
self._run_git('config', '--local', 'user.name', 'reno developer')
|
|
self._run_git('config', '--local', 'user.signingkey',
|
|
'example@example.com')
|
|
|
|
def _git_commit(self, message='commit message'):
|
|
self._run_git('add', '.')
|
|
self._run_git('commit', '-m', message)
|
|
|
|
def _add_other_file(self, name):
|
|
with open(os.path.join(self.reporoot, name), 'w') as f:
|
|
f.write('adding %s\n' % name)
|
|
self._git_commit('add %s' % name)
|
|
|
|
def _add_notes_file(self, slug='slug', commit=True, legacy=False):
|
|
n = self.get_note_num()
|
|
if legacy:
|
|
basename = '%016x-%s.yaml' % (n, slug)
|
|
else:
|
|
basename = '%s-%016x.yaml' % (slug, n)
|
|
filename = os.path.join(self.reporoot, 'releasenotes', 'notes',
|
|
basename)
|
|
create._make_note_file(filename)
|
|
self._git_commit('add %s' % basename)
|
|
return os.path.join('releasenotes', 'notes', basename)
|
|
|
|
def _make_python_package(self):
|
|
setup_name = os.path.join(self.reporoot, 'setup.py')
|
|
with open(setup_name, 'w') as f:
|
|
f.write(_SETUP_TEMPLATE)
|
|
cfg_name = os.path.join(self.reporoot, 'setup.cfg')
|
|
with open(cfg_name, 'w') as f:
|
|
f.write(_CFG_TEMPLATE)
|
|
pkgdir = os.path.join(self.reporoot, 'testpkg')
|
|
os.makedirs(pkgdir)
|
|
init = os.path.join(pkgdir, '__init__.py')
|
|
with open(init, 'w') as f:
|
|
f.write("Test package")
|
|
self._git_commit('add test package')
|
|
|
|
def setUp(self):
|
|
super(Base, self).setUp()
|
|
self.fake_logger = self.useFixture(
|
|
fixtures.FakeLogger(
|
|
format='%(levelname)8s %(name)s %(message)s',
|
|
level=logging.DEBUG,
|
|
nuke_handlers=True,
|
|
)
|
|
)
|
|
# Older git does not have config --local, so create a temporary home
|
|
# directory to permit using git config --global without stepping on
|
|
# developer configuration.
|
|
self.useFixture(fixtures.TempHomeDir())
|
|
self.useFixture(GPGKeyFixture())
|
|
self.useFixture(fixtures.NestedTempfile())
|
|
self.temp_dir = self.useFixture(fixtures.TempDir()).path
|
|
self.reporoot = os.path.join(self.temp_dir, 'reporoot')
|
|
self.c = config.Config(self.reporoot)
|
|
self._git_setup()
|
|
self._counter = itertools.count(1)
|
|
self.get_note_num = lambda: next(self._counter)
|
|
|
|
|
|
class BasicTest(Base):
|
|
|
|
def test_non_python_no_tags(self):
|
|
filename = self._add_notes_file()
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'0.0.0': [filename]},
|
|
results,
|
|
)
|
|
|
|
def test_python_no_tags(self):
|
|
self._make_python_package()
|
|
filename = self._add_notes_file()
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'0.0.0': [filename]},
|
|
results,
|
|
)
|
|
|
|
def test_note_before_tag(self):
|
|
filename = self._add_notes_file()
|
|
self._add_other_file('not-a-release-note.txt')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0': [filename]},
|
|
results,
|
|
)
|
|
|
|
def test_note_commit_tagged(self):
|
|
filename = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0': [filename]},
|
|
results,
|
|
)
|
|
|
|
def test_note_commit_after_tag(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
filename = self._add_notes_file()
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0-1': [filename]},
|
|
results,
|
|
)
|
|
|
|
def test_other_commit_after_tag(self):
|
|
filename = self._add_notes_file()
|
|
self._add_other_file('ignore-1.txt')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
self._add_other_file('ignore-2.txt')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0': [filename]},
|
|
results,
|
|
)
|
|
|
|
def test_multiple_notes_after_tag(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f1 = self._add_notes_file()
|
|
f2 = self._add_notes_file()
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0-2': [f1, f2]},
|
|
results,
|
|
)
|
|
|
|
def test_multiple_notes_within_tag(self):
|
|
self._make_python_package()
|
|
f1 = self._add_notes_file(commit=False)
|
|
f2 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0': [f1, f2]},
|
|
results,
|
|
)
|
|
|
|
def test_multiple_tags(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f1 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '2.0.0')
|
|
f2 = self._add_notes_file()
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'2.0.0': [f1],
|
|
'2.0.0-1': [f2],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_rename_file(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f1 = self._add_notes_file('slug1')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '2.0.0')
|
|
f2 = f1.replace('slug1', 'slug2')
|
|
self._run_git('mv', f1, f2)
|
|
self._git_commit('rename note file')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'2.0.0': [f2],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_rename_file_sort_earlier(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f1 = self._add_notes_file('slug1')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '2.0.0')
|
|
f2 = f1.replace('slug1', 'slug0')
|
|
self._run_git('mv', f1, f2)
|
|
self._git_commit('rename note file')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'2.0.0': [f2],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_edit_file(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f1 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '2.0.0')
|
|
with open(os.path.join(self.reporoot, f1), 'w') as f:
|
|
f.write('---\npreamble: new contents for file')
|
|
self._git_commit('edit note file')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'2.0.0': [f1],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_legacy_file(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f1 = self._add_notes_file('slug1', legacy=True)
|
|
self._run_git('tag', '-s', '-m', 'first tag', '2.0.0')
|
|
f2 = f1.replace('slug1', 'slug2')
|
|
self._run_git('mv', f1, f2)
|
|
self._git_commit('rename note file')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'2.0.0': [f2],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_rename_legacy_file_to_new(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f1 = self._add_notes_file('slug1', legacy=True)
|
|
self._run_git('tag', '-s', '-m', 'first tag', '2.0.0')
|
|
# Rename the file with the new convention of placing the UUID
|
|
# after the slug instead of before.
|
|
f2 = f1.replace('0000000000000001-slug1',
|
|
'slug1-0000000000000001')
|
|
self._run_git('mv', f1, f2)
|
|
self._git_commit('rename note file')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'2.0.0': [f2],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_limit_by_earliest_version(self):
|
|
self._make_python_package()
|
|
self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f2 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'middle tag', '2.0.0')
|
|
f3 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'last tag', '3.0.0')
|
|
self.c.override(
|
|
earliest_version='2.0.0',
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'2.0.0': [f2],
|
|
'3.0.0': [f3],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_delete_file(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f1 = self._add_notes_file('slug1')
|
|
f2 = self._add_notes_file('slug2')
|
|
self._run_git('rm', f1)
|
|
self._git_commit('remove note file')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '2.0.0')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'2.0.0': [f2],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_rename_then_delete_file(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
f1 = self._add_notes_file('slug1')
|
|
f2 = f1.replace('slug1', 'slug2')
|
|
self._run_git('mv', f1, f2)
|
|
self._run_git('status')
|
|
self._git_commit('rename note file')
|
|
self._run_git('rm', f2)
|
|
self._git_commit('remove note file')
|
|
f3 = self._add_notes_file('slug3')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '2.0.0')
|
|
log_results = self._run_git('log', '--topo-order',
|
|
'--pretty=%H %d',
|
|
'--name-only')
|
|
self.addDetail('git log', text_content(log_results))
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'2.0.0': [f3],
|
|
},
|
|
results,
|
|
)
|
|
|
|
|
|
class PreReleaseTest(Base):
|
|
|
|
def test_alpha(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0.0a1')
|
|
f1 = self._add_notes_file('slug1')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0.0a2')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0.0a2': [f1],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_beta(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0.0b1')
|
|
f1 = self._add_notes_file('slug1')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0.0b2')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0.0b2': [f1],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_release_candidate(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0.0rc1')
|
|
f1 = self._add_notes_file('slug1')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0.0rc2')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0.0rc2': [f1],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_collapse(self):
|
|
files = []
|
|
self._make_python_package()
|
|
files.append(self._add_notes_file('slug1'))
|
|
self._run_git('tag', '-s', '-m', 'alpha tag', '1.0.0.0a1')
|
|
files.append(self._add_notes_file('slug2'))
|
|
self._run_git('tag', '-s', '-m', 'beta tag', '1.0.0.0b1')
|
|
files.append(self._add_notes_file('slug3'))
|
|
self._run_git('tag', '-s', '-m', 'release candidate tag', '1.0.0.0rc1')
|
|
files.append(self._add_notes_file('slug4'))
|
|
self._run_git('tag', '-s', '-m', 'full release tag', '1.0.0')
|
|
self.c.override(
|
|
collapse_pre_releases=True,
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0': files,
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_collapse_without_full_release(self):
|
|
self._make_python_package()
|
|
f1 = self._add_notes_file('slug1')
|
|
self._run_git('tag', '-s', '-m', 'alpha tag', '1.0.0.0a1')
|
|
f2 = self._add_notes_file('slug2')
|
|
self._run_git('tag', '-s', '-m', 'beta tag', '1.0.0.0b1')
|
|
f3 = self._add_notes_file('slug3')
|
|
self._run_git('tag', '-s', '-m', 'release candidate tag', '1.0.0.0rc1')
|
|
self.c.override(
|
|
collapse_pre_releases=True,
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0.0a1': [f1],
|
|
'1.0.0.0b1': [f2],
|
|
'1.0.0.0rc1': [f3],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_collapse_without_notes(self):
|
|
self._make_python_package()
|
|
self._run_git('tag', '-s', '-m', 'earlier tag', '0.1.0')
|
|
f1 = self._add_notes_file('slug1')
|
|
self._run_git('tag', '-s', '-m', 'alpha tag', '1.0.0.0a1')
|
|
f2 = self._add_notes_file('slug2')
|
|
self._run_git('tag', '-s', '-m', 'beta tag', '1.0.0.0b1')
|
|
f3 = self._add_notes_file('slug3')
|
|
self._run_git('tag', '-s', '-m', 'release candidate tag', '1.0.0.0rc1')
|
|
self.c.override(
|
|
collapse_pre_releases=True,
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0.0a1': [f1],
|
|
'1.0.0.0b1': [f2],
|
|
'1.0.0.0rc1': [f3],
|
|
},
|
|
results,
|
|
)
|
|
|
|
|
|
class MergeCommitTest(Base):
|
|
|
|
def test_1(self):
|
|
# Create changes on master and in the branch
|
|
# in order so the history is "normal"
|
|
n1 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
self._run_git('checkout', '-b', 'test_merge_commit')
|
|
n2 = self._add_notes_file()
|
|
self._run_git('checkout', 'master')
|
|
self._add_other_file('ignore-1.txt')
|
|
self._run_git('merge', '--no-ff', 'test_merge_commit')
|
|
self._add_other_file('ignore-2.txt')
|
|
self._run_git('tag', '-s', '-m', 'second tag', '2.0.0')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0': [n1],
|
|
'2.0.0': [n2]},
|
|
results,
|
|
)
|
|
self.assertEqual(
|
|
['2.0.0', '1.0.0'],
|
|
list(raw_results.keys()),
|
|
)
|
|
|
|
def test_2(self):
|
|
# Create changes on the branch before the tag into which it is
|
|
# actually merged.
|
|
self._add_other_file('ignore-0.txt')
|
|
self._run_git('checkout', '-b', 'test_merge_commit')
|
|
n1 = self._add_notes_file()
|
|
self._run_git('checkout', 'master')
|
|
n2 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
self._add_other_file('ignore-1.txt')
|
|
self._run_git('merge', '--no-ff', 'test_merge_commit')
|
|
self._add_other_file('ignore-2.txt')
|
|
self._run_git('tag', '-s', '-m', 'second tag', '2.0.0')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0': [n2],
|
|
'2.0.0': [n1]},
|
|
results,
|
|
)
|
|
self.assertEqual(
|
|
['2.0.0', '1.0.0'],
|
|
list(raw_results.keys()),
|
|
)
|
|
|
|
def test_3(self):
|
|
# Create changes on the branch before the tag into which it is
|
|
# actually merged, with another tag in between the time of the
|
|
# commit and the time of the merge. This should reflect the
|
|
# order of events described in bug #1522153.
|
|
self._add_other_file('ignore-0.txt')
|
|
self._run_git('checkout', '-b', 'test_merge_commit')
|
|
n1 = self._add_notes_file()
|
|
self._run_git('checkout', 'master')
|
|
n2 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
self._add_other_file('ignore-1.txt')
|
|
self._run_git('tag', '-s', '-m', 'second tag', '1.1.0')
|
|
self._run_git('merge', '--no-ff', 'test_merge_commit')
|
|
self._add_other_file('ignore-2.txt')
|
|
self._run_git('tag', '-s', '-m', 'third tag', '2.0.0')
|
|
self._add_other_file('ignore-3.txt')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
# Since the 1.1.0 tag has no notes files, it does not appear
|
|
# in the output. It's only there to trigger the bug as it was
|
|
# originally reported.
|
|
self.assertEqual(
|
|
{'1.0.0': [n2],
|
|
'2.0.0': [n1]},
|
|
results,
|
|
)
|
|
self.assertEqual(
|
|
['2.0.0', '1.0.0'],
|
|
list(raw_results.keys()),
|
|
)
|
|
|
|
def test_4(self):
|
|
# Create changes on the branch before the tag into which it is
|
|
# actually merged, with another tag in between the time of the
|
|
# commit and the time of the merge. This should reflect the
|
|
# order of events described in bug #1522153.
|
|
self._add_other_file('ignore-0.txt')
|
|
self._run_git('checkout', '-b', 'test_merge_commit')
|
|
n1 = self._add_notes_file()
|
|
self._run_git('checkout', 'master')
|
|
n2 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
self._add_other_file('ignore-1.txt')
|
|
n3 = self._add_notes_file()
|
|
self._run_git('tag', '-s', '-m', 'second tag', '1.1.0')
|
|
self._run_git('merge', '--no-ff', 'test_merge_commit')
|
|
self._add_other_file('ignore-2.txt')
|
|
self._run_git('tag', '-s', '-m', 'third tag', '2.0.0')
|
|
self._add_other_file('ignore-3.txt')
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{'1.0.0': [n2],
|
|
'1.1.0': [n3],
|
|
'2.0.0': [n1]},
|
|
results,
|
|
)
|
|
self.assertEqual(
|
|
['2.0.0', '1.1.0', '1.0.0'],
|
|
list(raw_results.keys()),
|
|
)
|
|
|
|
|
|
class UniqueIdTest(Base):
|
|
|
|
def test_legacy(self):
|
|
uid = scanner._get_unique_id(
|
|
'releasenotes/notes/0000000000000001-slug1.yaml'
|
|
)
|
|
self.assertEqual('0000000000000001', uid)
|
|
|
|
def test_modern(self):
|
|
uid = scanner._get_unique_id(
|
|
'releasenotes/notes/slug1-0000000000000001.yaml'
|
|
)
|
|
self.assertEqual('0000000000000001', uid)
|
|
|
|
|
|
class BranchTest(Base):
|
|
|
|
def setUp(self):
|
|
super(BranchTest, self).setUp()
|
|
self._make_python_package()
|
|
self.f1 = self._add_notes_file('slug1')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '1.0.0')
|
|
self.f2 = self._add_notes_file('slug2')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '2.0.0')
|
|
self._add_notes_file('slug3')
|
|
self._run_git('tag', '-s', '-m', 'first tag', '3.0.0')
|
|
|
|
def test_files_current_branch(self):
|
|
self._run_git('checkout', '2.0.0')
|
|
self._run_git('checkout', '-b', 'stable/2')
|
|
f21 = self._add_notes_file('slug21')
|
|
log_text = self._run_git('log')
|
|
self.addDetail('git log', text_content(log_text))
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{
|
|
'1.0.0': [self.f1],
|
|
'2.0.0': [self.f2],
|
|
'2.0.0-1': [f21],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_files_stable_from_master(self):
|
|
self._run_git('checkout', '2.0.0')
|
|
self._run_git('checkout', '-b', 'stable/2')
|
|
f21 = self._add_notes_file('slug21')
|
|
self._run_git('checkout', 'master')
|
|
log_text = self._run_git('log', '--pretty=%x00%H %d', '--name-only',
|
|
'stable/2')
|
|
self.addDetail('git log', text_content(log_text))
|
|
self.c.override(
|
|
branch='stable/2',
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{
|
|
'2.0.0': [self.f2],
|
|
'2.0.0-1': [f21],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_pre_release_branch_no_collapse(self):
|
|
f4 = self._add_notes_file('slug4')
|
|
self._run_git('tag', '-s', '-m', 'pre-release', '4.0.0.0rc1')
|
|
# Add a commit on master after the tag
|
|
self._add_notes_file('slug5')
|
|
# Move back to the tag and create the branch
|
|
self._run_git('checkout', '4.0.0.0rc1')
|
|
self._run_git('checkout', '-b', 'stable/4')
|
|
# Create a commit on the branch
|
|
f41 = self._add_notes_file('slug41')
|
|
log_text = self._run_git(
|
|
'log', '--pretty=%x00%H %d', '--name-only', '--graph',
|
|
'--all', '--decorate',
|
|
)
|
|
self.addDetail('git log', text_content(log_text))
|
|
rev_list = self._run_git('rev-list', '--first-parent',
|
|
'^stable/4', 'master')
|
|
self.addDetail('rev-list', text_content(rev_list))
|
|
self.c.override(
|
|
branch='stable/4',
|
|
collapse_pre_releases=False,
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{
|
|
'4.0.0.0rc1': [f4],
|
|
'4.0.0.0rc1-1': [f41],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_pre_release_branch_collapse(self):
|
|
f4 = self._add_notes_file('slug4')
|
|
self._run_git('tag', '-s', '-m', 'pre-release', '4.0.0.0rc1')
|
|
# Add a commit on master after the tag
|
|
self._add_notes_file('slug5')
|
|
# Move back to the tag and create the branch
|
|
self._run_git('checkout', '4.0.0.0rc1')
|
|
self._run_git('checkout', '-b', 'stable/4')
|
|
# Create a commit on the branch
|
|
f41 = self._add_notes_file('slug41')
|
|
self._run_git('tag', '-s', '-m', 'release', '4.0.0')
|
|
log_text = self._run_git(
|
|
'log', '--pretty=%x00%H %d', '--name-only', '--graph',
|
|
'--all', '--decorate',
|
|
)
|
|
self.addDetail('git log', text_content(log_text))
|
|
rev_list = self._run_git('rev-list', '--first-parent',
|
|
'^stable/4', 'master')
|
|
self.addDetail('rev-list', text_content(rev_list))
|
|
self.c.override(
|
|
branch='stable/4',
|
|
collapse_pre_releases=True,
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{
|
|
'4.0.0': [f4, f41],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_full_release_branch(self):
|
|
f4 = self._add_notes_file('slug4')
|
|
self._run_git('tag', '-s', '-m', 'release', '4.0.0')
|
|
# Add a commit on master after the tag
|
|
self._add_notes_file('slug5')
|
|
# Move back to the tag and create the branch
|
|
self._run_git('checkout', '4.0.0')
|
|
self._run_git('checkout', '-b', 'stable/4')
|
|
# Create a commit on the branch
|
|
f41 = self._add_notes_file('slug41')
|
|
log_text = self._run_git(
|
|
'log', '--pretty=%x00%H %d', '--name-only', '--graph',
|
|
'--all', '--decorate',
|
|
)
|
|
self.addDetail('git log', text_content(log_text))
|
|
rev_list = self._run_git('rev-list', '--first-parent',
|
|
'^stable/4', 'master')
|
|
self.addDetail('rev-list', text_content(rev_list))
|
|
self.c.override(
|
|
branch='stable/4',
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{
|
|
'4.0.0': [f4],
|
|
'4.0.0-1': [f41],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_branch_tip_of_master(self):
|
|
# We have branched from master, but not added any commits to
|
|
# master.
|
|
f4 = self._add_notes_file('slug4')
|
|
self._run_git('tag', '-s', '-m', 'release', '4.0.0')
|
|
self._run_git('checkout', '-b', 'stable/4')
|
|
# Create a commit on the branch
|
|
f41 = self._add_notes_file('slug41')
|
|
f42 = self._add_notes_file('slug42')
|
|
log_text = self._run_git(
|
|
'log', '--pretty=%x00%H %d', '--name-only', '--graph',
|
|
'--all', '--decorate',
|
|
)
|
|
self.addDetail('git log', text_content(log_text))
|
|
rev_list = self._run_git('rev-list', '--first-parent',
|
|
'^stable/4', 'master')
|
|
self.addDetail('rev-list', text_content(rev_list))
|
|
self.c.override(
|
|
branch='stable/4',
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{
|
|
'4.0.0': [f4],
|
|
'4.0.0-2': [f41, f42],
|
|
},
|
|
results,
|
|
)
|
|
|
|
def test_branch_no_more_commits(self):
|
|
# We have branched from master, but not added any commits to
|
|
# our branch or to master.
|
|
f4 = self._add_notes_file('slug4')
|
|
self._run_git('tag', '-s', '-m', 'release', '4.0.0')
|
|
self._run_git('checkout', '-b', 'stable/4')
|
|
# Create a commit on the branch
|
|
log_text = self._run_git(
|
|
'log', '--pretty=%x00%H %d', '--name-only', '--graph',
|
|
'--all', '--decorate',
|
|
)
|
|
self.addDetail('git log', text_content(log_text))
|
|
rev_list = self._run_git('rev-list', '--first-parent',
|
|
'^stable/4', 'master')
|
|
self.addDetail('rev-list', text_content(rev_list))
|
|
self.c.override(
|
|
branch='stable/4',
|
|
)
|
|
raw_results = scanner.get_notes_by_version(self.c)
|
|
results = {
|
|
k: [f for (f, n) in v]
|
|
for (k, v) in raw_results.items()
|
|
}
|
|
self.assertEqual(
|
|
{
|
|
'4.0.0': [f4],
|
|
},
|
|
results,
|
|
)
|
|
|
|
|
|
class GetTagsParseTest(base.TestCase):
|
|
|
|
EXPECTED = [
|
|
'2.0.0',
|
|
'1.8.1',
|
|
'1.8.0',
|
|
'1.7.1',
|
|
'1.7.0',
|
|
'1.6.0',
|
|
'1.5.0',
|
|
'1.4.0',
|
|
'1.3.0',
|
|
'1.2.0',
|
|
'1.1.0',
|
|
'1.0.0',
|
|
'0.11.2',
|
|
'0.11.1',
|
|
'0.11.0',
|
|
'0.10.1',
|
|
'0.10.0',
|
|
'0.9.0',
|
|
'0.8.0',
|
|
'0.7.1',
|
|
'0.7.0',
|
|
'0.6.0',
|
|
'0.5.1',
|
|
'0.5.0',
|
|
'0.4.2',
|
|
'0.4.1',
|
|
'0.4.0',
|
|
'0.3.2',
|
|
'0.3.1',
|
|
'0.3.0',
|
|
'0.2.5',
|
|
'0.2.4',
|
|
'0.2.3',
|
|
'0.2.2',
|
|
'0.2.1',
|
|
'0.2.0',
|
|
'0.1.3',
|
|
'0.1.2',
|
|
'0.1.1',
|
|
'0.1.0',
|
|
]
|
|
|
|
def test_keystoneclient_ubuntu_1_9_1(self):
|
|
# git 1.9.1 as it produces output on ubuntu for python-keystoneclient
|
|
# git log --simplify-by-decoration --pretty="%d"
|
|
tag_list_output = textwrap.dedent("""
|
|
(HEAD, origin/master, origin/HEAD, gerrit/master, master)
|
|
(apu/master)
|
|
(tag: 2.0.0)
|
|
(tag: 1.8.1)
|
|
(tag: 1.8.0)
|
|
(tag: 1.7.1)
|
|
(tag: 1.7.0)
|
|
(tag: 1.6.0)
|
|
(tag: 1.5.0)
|
|
(tag: 1.4.0)
|
|
(uncap-requirements)
|
|
(tag: 1.3.0)
|
|
(tag: 1.2.0)
|
|
(tag: 1.1.0)
|
|
(tag: 1.0.0)
|
|
(tag: 0.11.2)
|
|
(tag: 0.11.1)
|
|
(tag: 0.11.0)
|
|
(tag: 0.10.1)
|
|
(tag: 0.10.0)
|
|
(tag: 0.9.0)
|
|
(tag: 0.8.0)
|
|
(tag: 0.7.1)
|
|
(tag: 0.7.0)
|
|
(tag: 0.6.0)
|
|
(tag: 0.5.1)
|
|
(tag: 0.5.0)
|
|
(tag: 0.4.2)
|
|
(tag: 0.4.1)
|
|
(tag: 0.4.0)
|
|
(tag: 0.3.2)
|
|
(tag: 0.3.1)
|
|
(tag: 0.3.0)
|
|
(tag: 0.2.5)
|
|
(tag: 0.2.4)
|
|
(tag: 0.2.3)
|
|
(tag: 0.2.2)
|
|
(tag: 0.2.1)
|
|
(tag: 0.2.0)
|
|
|
|
(origin/feature/keystone-v3, gerrit/feature/keystone-v3)
|
|
(tag: 0.1.3)
|
|
(tag: 0.1.2)
|
|
(tag: 0.1.1)
|
|
(tag: 0.1.0)
|
|
(tag: folsom-1)
|
|
(tag: essex-rc1)
|
|
(tag: essex-4)
|
|
(tag: essex-3)
|
|
""")
|
|
with mock.patch('reno.utils.check_output') as co:
|
|
co.return_value = tag_list_output
|
|
actual = scanner._get_version_tags_on_branch('reporoot',
|
|
branch=None)
|
|
self.assertEqual(self.EXPECTED, actual)
|
|
|
|
def test_keystoneclient_rhel_1_7_1(self):
|
|
# git 1.7.1 as it produces output on RHEL 6 for python-keystoneclient
|
|
# git log --simplify-by-decoration --pretty="%d"
|
|
tag_list_output = textwrap.dedent("""
|
|
(HEAD, origin/master, origin/HEAD, master)
|
|
(tag: 2.0.0)
|
|
(tag: 1.8.1)
|
|
(tag: 1.8.0)
|
|
(tag: 1.7.1)
|
|
(tag: 1.7.0)
|
|
(tag: 1.6.0)
|
|
(tag: 1.5.0)
|
|
(tag: 1.4.0)
|
|
(tag: 1.3.0)
|
|
(tag: 1.2.0)
|
|
(tag: 1.1.0)
|
|
(tag: 1.0.0)
|
|
(tag: 0.11.2)
|
|
(tag: 0.11.1)
|
|
(tag: 0.11.0)
|
|
(tag: 0.10.1)
|
|
(tag: 0.10.0)
|
|
(tag: 0.9.0)
|
|
(tag: 0.8.0)
|
|
(tag: 0.7.1)
|
|
(tag: 0.7.0)
|
|
(tag: 0.6.0)
|
|
(tag: 0.5.1)
|
|
(tag: 0.5.0)
|
|
(tag: 0.4.2)
|
|
(tag: 0.4.1)
|
|
(tag: 0.4.0)
|
|
(tag: 0.3.2)
|
|
(tag: 0.3.1)
|
|
(tag: 0.3.0)
|
|
(tag: 0.2.5)
|
|
(tag: 0.2.4)
|
|
(tag: 0.2.3)
|
|
(tag: 0.2.2)
|
|
(tag: 0.2.1)
|
|
(tag: 0.2.0)
|
|
(tag: 0.1.3)
|
|
(0.1.2)
|
|
(tag: 0.1.1)
|
|
(0.1.0)
|
|
(tag: folsom-1)
|
|
(tag: essex-rc1)
|
|
(essex-4)
|
|
(essex-3)
|
|
""")
|
|
with mock.patch('reno.utils.check_output') as co:
|
|
co.return_value = tag_list_output
|
|
actual = scanner._get_version_tags_on_branch('reporoot',
|
|
branch=None)
|
|
self.assertEqual(self.EXPECTED, actual)
|