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
This commit is contained in:
parent
bbe3543f78
commit
93a063978e
@ -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 ...
|
... 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
|
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``.
|
By default, the new note is created under ``./releasenotes/notes``.
|
||||||
The ``--rel-notes-dir`` command-line flag changes the parent directory
|
The ``--rel-notes-dir`` command-line flag changes the parent directory
|
||||||
|
@ -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.
|
@ -47,6 +47,16 @@ def _edit_file(filename):
|
|||||||
return True
|
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):
|
def create_cmd(args, conf):
|
||||||
"Create a new release note file from the template."
|
"Create a new release note file from the template."
|
||||||
# NOTE(dhellmann): There is a short race window where we might try
|
# NOTE(dhellmann): There is a short race window where we might try
|
||||||
@ -57,7 +67,11 @@ def create_cmd(args, conf):
|
|||||||
# concern.
|
# concern.
|
||||||
slug = args.slug.replace(' ', '-')
|
slug = args.slug.replace(' ', '-')
|
||||||
filename = _pick_note_file_name(conf.notespath, slug)
|
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):
|
if args.edit and not _edit_file(filename):
|
||||||
print('Was unable to edit the new note. EDITOR environment variable '
|
print('Was unable to edit the new note. EDITOR environment variable '
|
||||||
'is missing!')
|
'is missing!')
|
||||||
|
@ -99,6 +99,10 @@ def main(argv=sys.argv[1:]):
|
|||||||
action='store_true',
|
action='store_true',
|
||||||
help='Edit note after its creation (require EDITOR env variable)',
|
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(
|
do_new.add_argument(
|
||||||
'slug',
|
'slug',
|
||||||
help='descriptive title of note (keep it short)',
|
help='descriptive title of note (keep it short)',
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import fixtures
|
import fixtures
|
||||||
|
import io
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from reno import create
|
from reno import create
|
||||||
@ -45,6 +46,16 @@ class TestCreate(base.TestCase):
|
|||||||
super(TestCreate, self).setUp()
|
super(TestCreate, self).setUp()
|
||||||
self.tmpdir = self.useFixture(fixtures.TempDir()).path
|
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):
|
def test_create_from_template(self):
|
||||||
filename = create._pick_note_file_name(self.tmpdir, 'theslug')
|
filename = create._pick_note_file_name(self.tmpdir, 'theslug')
|
||||||
create._make_note_file(filename, 'i-am-a-template')
|
create._make_note_file(filename, 'i-am-a-template')
|
||||||
@ -52,6 +63,29 @@ class TestCreate(base.TestCase):
|
|||||||
body = f.read()
|
body = f.read()
|
||||||
self.assertEqual('i-am-a-template', body)
|
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):
|
def test_edit(self):
|
||||||
self.useFixture(fixtures.EnvironmentVariable('EDITOR', 'myeditor'))
|
self.useFixture(fixtures.EnvironmentVariable('EDITOR', 'myeditor'))
|
||||||
with mock.patch('subprocess.call') as call_mock:
|
with mock.patch('subprocess.call') as call_mock:
|
||||||
|
Loading…
Reference in New Issue
Block a user