Skip to content

Commit 666589c

Browse files
committed
Add a print subcommand
Closes #115
1 parent 269dd08 commit 666589c

File tree

6 files changed

+160
-2
lines changed

6 files changed

+160
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Added
2+
.....
3+
4+
- Add a ``print`` subcommand that can write changelog entries to STDOUT
5+
or to a file.

docs/commands.rst

+26
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,30 @@ If your changelog file is in reStructuredText format, you will need `pandoc`_
230230

231231
.. _pandoc: https://pandoc.org/
232232

233+
scriv github-release
234+
====================
235+
236+
.. [[[cog show_help("print") ]]]
237+
238+
.. code::
239+
240+
$ scriv print --help
241+
Usage: scriv print [OPTIONS]
242+
243+
Print collected fragments, or print an entry from the changelog.
244+
245+
Options:
246+
--version TEXT The version of the changelog entry to extract.
247+
--output PATH The path to a file to write the output to.
248+
-v, --verbosity LVL Either CRITICAL, ERROR, WARNING, INFO or DEBUG
249+
--help Show this message and exit.
250+
.. [[[end]]] (checksum: f652a3470da5f726b13ba076471b2444)
251+
252+
The ``print`` command writes a changelog entry to STDOUT.
253+
254+
If ``--output`` is provided, the changelog entry is written to the given file.
255+
256+
If ``--version`` is given, the changelog entry is extracted from the CHANGELOG;
257+
if not, then the changelog entry is generated from fragment files.
258+
233259
.. include:: include/links.rst

src/scriv/cli.py

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from .collect import collect
1010
from .create import create
1111
from .ghrel import github_release
12+
from .print import print_
1213

1314
click_log.basic_config(logging.getLogger())
1415

@@ -28,3 +29,4 @@ def cli() -> None: # noqa: D401
2829
cli.add_command(create)
2930
cli.add_command(collect)
3031
cli.add_command(github_release)
32+
cli.add_command(print_)

src/scriv/print.py

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Collecting fragments."""
2+
3+
from __future__ import annotations
4+
5+
import logging
6+
import os
7+
import pathlib
8+
import sys
9+
10+
import click
11+
12+
from .scriv import Scriv
13+
from .util import Version, scriv_command
14+
15+
logger = logging.getLogger(__name__)
16+
17+
18+
@click.command(name="print")
19+
@click.option(
20+
"--version",
21+
default=None,
22+
help="The version of the changelog entry to extract.",
23+
)
24+
@click.option(
25+
"--output",
26+
type=click.Path(),
27+
default=None,
28+
help="The path to a file to write the output to.",
29+
)
30+
@scriv_command
31+
def print_(
32+
version: str | None,
33+
output: pathlib.Path | None,
34+
) -> None:
35+
"""
36+
Print collected fragments, or print an entry from the changelog.
37+
"""
38+
scriv = Scriv()
39+
changelog = scriv.changelog()
40+
newline = os.linesep
41+
42+
if version is None:
43+
logger.info(f"Generating entry from {scriv.config.fragment_directory}")
44+
frags = scriv.fragments_to_combine()
45+
if not frags:
46+
logger.info("No changelog fragments to collect")
47+
sys.exit(2)
48+
contents = changelog.entry_text(scriv.combine_fragments(frags)).strip()
49+
else:
50+
logger.info(f"Extracting entry for {version} from {changelog.path}")
51+
changelog.read()
52+
newline = changelog.newline
53+
target_version = Version(version)
54+
for etitle, sections in changelog.entries().items():
55+
if etitle is None:
56+
continue
57+
eversion = Version.from_text(etitle)
58+
if eversion == target_version:
59+
contents = f"{changelog.newline * 2}".join(sections).strip()
60+
break
61+
else:
62+
logger.info(f"Unable to find version {version} in the changelog")
63+
sys.exit(2)
64+
65+
if output:
66+
with open(output, "wt", encoding="utf-8", newline=newline) as file:
67+
file.write(contents)
68+
else:
69+
print(contents)

tests/conftest.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ def cli_invoke(temp_dir: Path):
6161
"""
6262

6363
def invoke(command, expect_ok=True):
64-
runner = CliRunner()
64+
runner = CliRunner(mix_stderr=False)
6565
result = runner.invoke(scriv_cli, command)
66-
print(result.output)
66+
print(result.stdout, end="")
67+
print(result.stderr, end="", file=sys.stderr)
6768
if result.exception:
6869
traceback.print_exception(
6970
None, result.exception, result.exception.__traceback__

tests/test_print.py

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""Test print logic."""
2+
3+
import freezegun
4+
5+
CHANGELOG_HEADER = """\
6+
7+
1.2 - 2020-02-25
8+
================
9+
"""
10+
11+
12+
FRAG = """\
13+
Fixed
14+
-----
15+
16+
- Launching missiles no longer targets ourselves.
17+
"""
18+
19+
20+
def test_print_fragment(cli_invoke, changelog_d, temp_dir, capsys):
21+
# Sections are ordered by the config file.
22+
# Fragments in sections are in time order.
23+
(changelog_d / "20170616_nedbat.rst").write_text(FRAG)
24+
with freezegun.freeze_time("2020-02-25T15:18:19"):
25+
cli_invoke(["print"])
26+
std = capsys.readouterr()
27+
assert std.out == FRAG
28+
29+
30+
def test_print_fragment_output(cli_invoke, changelog_d, temp_dir, capsys):
31+
(changelog_d / "20170616_nedbat.rst").write_text(FRAG)
32+
output_file = temp_dir / "output.txt"
33+
with freezegun.freeze_time("2020-02-25T15:18:19"):
34+
cli_invoke(["print", "--output", output_file])
35+
std = capsys.readouterr()
36+
assert std.out == ""
37+
assert output_file.read_text().strip() == FRAG.strip()
38+
39+
40+
def test_print_changelog(cli_invoke, changelog_d, temp_dir, capsys):
41+
(temp_dir / "CHANGELOG.rst").write_text(CHANGELOG_HEADER + FRAG)
42+
with freezegun.freeze_time("2020-02-25T15:18:19"):
43+
cli_invoke(["print", "--version", "1.2"])
44+
std = capsys.readouterr()
45+
assert std.out == FRAG
46+
47+
48+
def test_print_changelog_output(cli_invoke, changelog_d, temp_dir, capsys):
49+
(temp_dir / "CHANGELOG.rst").write_text(CHANGELOG_HEADER + FRAG)
50+
output_file = temp_dir / "output.txt"
51+
with freezegun.freeze_time("2020-02-25T15:18:19"):
52+
cli_invoke(["print", "--version", "1.2", "--output", output_file])
53+
std = capsys.readouterr()
54+
assert std.out == ""
55+
assert output_file.read_text().strip() == FRAG.strip()

0 commit comments

Comments
 (0)