From 93a063978e07caacdbc36a500a565599ac022887 Mon Sep 17 00:00:00 2001 From: Juan Antonio Osorio Robles Date: Fri, 13 Oct 2017 09:13:57 +0300 Subject: [PATCH] Add option to create release note from user-provided template This is useful when automating the release note creation (when automating commit creation). Change-Id: I11793aaa3232b0f2c44521a998d466f427eecd93 --- doc/source/user/usage.rst | 14 ++++++++ ...-using-tempalte-file-be734d8698309409.yaml | 6 ++++ reno/create.py | 16 ++++++++- reno/main.py | 4 +++ reno/tests/test_create.py | 34 +++++++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/Enable-using-tempalte-file-be734d8698309409.yaml diff --git a/doc/source/user/usage.rst b/doc/source/user/usage.rst index 71835f4..3aa69ed 100644 --- a/doc/source/user/usage.rst +++ b/doc/source/user/usage.rst @@ -40,6 +40,20 @@ The ``--edit`` option opens the new note in a text editor. ... Opens the editor set in the EDITOR environment variable, editing the new file ... Created new notes file in releasenotes/notes/slug-goes-here-95915aaedd3c48d8.yaml +The ``--from-template`` option allows you to use a pre-defined file and use +that as the release note. + +:: + + $ reno new slug-goes-here --from-template my-file.yaml + ... Creates a release note using the provided file my-file.yaml ... + Created new notes file in releasenotes/notes/slug-goes-here-95915aaedd3c48d8.yaml + +.. note:: + + You can also combine the flags ``--edit`` and ``--from-template`` + to create a release note from a specified file and immediately start an + editor to modify the new file. By default, the new note is created under ``./releasenotes/notes``. The ``--rel-notes-dir`` command-line flag changes the parent directory diff --git a/releasenotes/notes/Enable-using-tempalte-file-be734d8698309409.yaml b/releasenotes/notes/Enable-using-tempalte-file-be734d8698309409.yaml new file mode 100644 index 0000000..68a82ff --- /dev/null +++ b/releasenotes/notes/Enable-using-tempalte-file-be734d8698309409.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The --from-template flag was added to the release note creation command. + This enables one to create a release note from a pre-defined template, + which is useful when automating the creation of commits. diff --git a/reno/create.py b/reno/create.py index 0b5e0ea..703e641 100644 --- a/reno/create.py +++ b/reno/create.py @@ -47,6 +47,16 @@ def _edit_file(filename): return True +def _get_user_template(template_file): + if not os.path.exists(template_file): + raise ValueError( + 'The provided template file %s doesn\'t ' + 'exist' % template_file, + ) + with open(template_file, 'r') as f: + return f.read() + + def create_cmd(args, conf): "Create a new release note file from the template." # NOTE(dhellmann): There is a short race window where we might try @@ -57,7 +67,11 @@ def create_cmd(args, conf): # concern. slug = args.slug.replace(' ', '-') filename = _pick_note_file_name(conf.notespath, slug) - _make_note_file(filename, conf.template) + if args.from_template: + template = _get_user_template(args.from_template) + else: + template = conf.template + _make_note_file(filename, template) if args.edit and not _edit_file(filename): print('Was unable to edit the new note. EDITOR environment variable ' 'is missing!') diff --git a/reno/main.py b/reno/main.py index 3237661..51e40b9 100644 --- a/reno/main.py +++ b/reno/main.py @@ -99,6 +99,10 @@ def main(argv=sys.argv[1:]): action='store_true', help='Edit note after its creation (require EDITOR env variable)', ) + do_new.add_argument( + '--from-template', + help='Template to get the release note from.', + ) do_new.add_argument( 'slug', help='descriptive title of note (keep it short)', diff --git a/reno/tests/test_create.py b/reno/tests/test_create.py index 2ad374a..46cb9b0 100644 --- a/reno/tests/test_create.py +++ b/reno/tests/test_create.py @@ -13,6 +13,7 @@ # under the License. import fixtures +import io import mock from reno import create @@ -45,6 +46,16 @@ class TestCreate(base.TestCase): super(TestCreate, self).setUp() self.tmpdir = self.useFixture(fixtures.TempDir()).path + def _create_user_template(self, contents): + filename = create._pick_note_file_name(self.tmpdir, 'usertemplate') + with open(filename, 'w') as f: + f.write(contents) + return filename + + def _get_file_path_from_output(self, output): + # Get the last consecutive word from the output and remove the newline + return output[output.rfind(" ") + 1:-1] + def test_create_from_template(self): filename = create._pick_note_file_name(self.tmpdir, 'theslug') create._make_note_file(filename, 'i-am-a-template') @@ -52,6 +63,29 @@ class TestCreate(base.TestCase): body = f.read() self.assertEqual('i-am-a-template', body) + def test_create_from_user_template(self): + args = mock.Mock() + args.from_template = self._create_user_template('i-am-a-user-template') + args.slug = 'theslug' + args.edit = False + conf = mock.Mock() + conf.notespath = self.tmpdir + with mock.patch('sys.stdout', new=io.StringIO()) as fake_out: + create.create_cmd(args, conf) + filename = self._get_file_path_from_output(fake_out.getvalue()) + with open(filename, 'r') as f: + body = f.read() + self.assertEqual('i-am-a-user-template', body) + + def test_create_from_user_template_fails_because_unexistent_file(self): + args = mock.Mock() + args.from_template = 'some-unexistent-file.yaml' + args.slug = 'theslug' + args.edit = False + conf = mock.Mock() + conf.notespath = self.tmpdir + self.assertRaises(ValueError, create.create_cmd, args, conf) + def test_edit(self): self.useFixture(fixtures.EnvironmentVariable('EDITOR', 'myeditor')) with mock.patch('subprocess.call') as call_mock: