File: changelog_formatter.py

package info (click to toggle)
celery 5.5.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 8,008 kB
  • sloc: python: 64,346; sh: 795; makefile: 378
file content (130 lines) | stat: -rwxr-xr-x 3,034 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python3

import re
import sys

import click
import pyperclip
from colorama import Fore, init

# Initialize colorama for color support in terminal
init(autoreset=True)

# Regular expression pattern to match the required lines
PATTERN = re.compile(r"^\*\s*(.*?)\s+by\s+@[\w-]+\s+in\s+https://github\.com/[\w-]+/[\w-]+/pull/(\d+)")


def read_changes_file(filename):
    try:
        with open(filename) as f:
            return f.readlines()
    except FileNotFoundError:
        print(f"Error: {filename} file not found.")
        sys.exit(1)


def read_from_clipboard():
    text = pyperclip.paste()
    return text.splitlines()


def process_line(line):
    line = line.strip()

    # Skip lines containing '[pre-commit.ci]'
    if "[pre-commit.ci]" in line:
        return None

    # Skip lines starting with '## What's Changed'
    if line.startswith("## What's Changed"):
        return None

    # Stop processing if '## New Contributors' is encountered
    if line.startswith("## New Contributors"):
        return "STOP_PROCESSING"

    # Skip lines that don't start with '* '
    if not line.startswith("* "):
        return None

    match = PATTERN.match(line)
    if match:
        description, pr_number = match.groups()
        return f"- {description} (#{pr_number})"
    return None


@click.command()
@click.option(
    "--source",
    "-s",
    type=click.Path(exists=True),
    help="Source file to read from. If not provided, reads from clipboard.",
)
@click.option(
    "--dest",
    "-d",
    type=click.File("w"),
    default="-",
    help="Destination file to write to. Defaults to standard output.",
)
@click.option(
    "--clipboard",
    "-c",
    is_flag=True,
    help="Read input from clipboard explicitly.",
)
def main(source, dest, clipboard):
    # Determine the source of input
    if clipboard or (not source and not sys.stdin.isatty()):
        # Read from clipboard
        lines = read_from_clipboard()
    elif source:
        # Read from specified file
        lines = read_changes_file(source)
    else:
        # Default: read from clipboard
        lines = read_from_clipboard()

    output_lines = []
    for line in lines:
        output_line = process_line(line)
        if output_line == "STOP_PROCESSING":
            break
        if output_line:
            output_lines.append(output_line)

    output_text = "\n".join(output_lines)

    # Prepare the header
    version = "x.y.z"
    underline = "=" * len(version)

    header = f"""
.. _version-{version}:

{version}
{underline}

:release-date: <YYYY-MM-DD>
:release-by: <FULL NAME>

What's Changed
~~~~~~~~~~~~~~
"""

    # Combine header and output
    final_output = header + output_text

    # Write output to destination
    if dest.name == "<stdout>":
        print(Fore.GREEN + "Copy the following text to Changelog.rst:")
        print(Fore.YELLOW + header)
        print(Fore.CYAN + output_text)
    else:
        dest.write(final_output + "\n")
        dest.close()


if __name__ == "__main__":
    main()