pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/leodevian/modern-python/commit/913ffb67b87f8d4c4c73946f19de82e879198615

" /> chore: automate releases · leodevian/modern-python@913ffb6 · GitHub
Skip to content

Commit 913ffb6

Browse files
committed
chore: automate releases
1 parent 03fa586 commit 913ffb6

File tree

4 files changed

+190
-2
lines changed

4 files changed

+190
-2
lines changed

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ lint = [
6363
"pre-commit-uv>=4.1.4",
6464
]
6565
release = [
66+
"packaging>=24.2",
6667
"towncrier>=24.8",
68+
"uv>=0.7.7",
6769
]
6870

6971
[tool.ruff]

scripts/release.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# //github.com/ script
2+
# requires-python = ">=3.10"
3+
# dependencies = [
4+
# "packaging>=24.2",
5+
# "towncrier>=24.8",
6+
# "uv>=0.7.7",
7+
# ]
8+
# //github.com/
9+
"""Automation for releases."""
10+
11+
# ruff: noqa: T201
12+
13+
from __future__ import annotations
14+
15+
import argparse
16+
import subprocess
17+
import sys
18+
from functools import partial
19+
from typing import TYPE_CHECKING
20+
21+
from packaging.version import Version
22+
23+
if TYPE_CHECKING:
24+
from collections.abc import Sequence
25+
26+
print_error = partial(print, file=sys.stderr)
27+
28+
run = partial(
29+
subprocess.check_call,
30+
stdout=subprocess.DEVNULL,
31+
stderr=subprocess.DEVNULL,
32+
)
33+
34+
35+
def main(argv: Sequence[str] | None = None) -> int: # noqa: PLR0911, PLR0915
36+
"""Prepare a new release."""
37+
# Parse command-line arguments.
38+
parser = argparse.ArgumentParser(description="prepare a new release")
39+
parser.add_argument(
40+
"--version",
41+
type=Version,
42+
required=True,
43+
help="provide the release version",
44+
)
45+
parser.add_argument(
46+
"--dry-run",
47+
action="store_true",
48+
help="perform a dry run",
49+
)
50+
args = parser.parse_args(argv)
51+
52+
# Get the public portion of the version.
53+
version = args.version.public
54+
55+
# Check if the Git repository is dirty.
56+
try:
57+
run(("git", "diff", "--quiet"))
58+
59+
except subprocess.CalledProcessError:
60+
print_error("The Git repository is dirty.")
61+
return 1
62+
63+
# Get the name of the base branch.
64+
base_branch = subprocess.check_output(
65+
("git", "rev-parse", "--abbrev-ref", "HEAD"),
66+
encoding="utf-8",
67+
).rstrip()
68+
69+
# Create the release branch.
70+
release_branch = f"release/{version}"
71+
72+
try:
73+
run(("git", "branch", release_branch))
74+
75+
except subprocess.CalledProcessError:
76+
print_error(f"The release branch already exists: {release_branch!r}.")
77+
return 1
78+
79+
print(f"Created release branch {release_branch!r}.")
80+
81+
# Switch to the release branch.
82+
run(("git", "checkout", release_branch))
83+
84+
print(f"Switched from branch {base_branch!r} to release branch {release_branch!r}.")
85+
86+
# Bump the version.
87+
try:
88+
run(("uv", "version", "--no-sync", version))
89+
run(("towncrier", "build", "--yes", "--version", version))
90+
91+
except subprocess.CalledProcessError:
92+
run(("git", "checkout", base_branch))
93+
run(("git", "branch", "-D", release_branch))
94+
print_error("An error occurred while bumping the version.")
95+
print_error(
96+
f"Removed release branch {release_branch!r} "
97+
f"and switched back to {base_branch!r}."
98+
)
99+
return 1
100+
101+
# Commit changes.
102+
run(("git", "add", ":/pyproject.toml", ":/uv.lock"))
103+
run(("git", "add", "-A", ":/changelog.d/*", ":/CHANGELOG.md"))
104+
run(("git", "commit", "-m", f"chore: prepare release {version}", "--no-verify"))
105+
106+
print(f"Committed changes on branch {release_branch!r}.")
107+
108+
# Create the release tag.
109+
release_tag = f"v{version}"
110+
111+
try:
112+
run(("git", "tag", "-a", release_tag, "-m", f"bump version to {version}"))
113+
114+
except subprocess.CalledProcessError:
115+
run(("git", "checkout", base_branch))
116+
run(("git", "branch", "-D", release_branch))
117+
print_error(f"The release tag already exists: {release_tag!r}.")
118+
print_error(
119+
f"Removed release branch {release_branch!r} "
120+
f"and switched back to {base_branch!r}."
121+
)
122+
return 1
123+
124+
# Exit on dry run.
125+
if args.dry_run:
126+
print("Dry run success!")
127+
run(("git", "checkout", base_branch))
128+
run(("git", "branch", "-D", release_branch))
129+
print(
130+
f"Removed release branch {release_branch!r} "
131+
f"and switched back to {base_branch!r}."
132+
)
133+
run(("git", "tag", "-d", release_tag))
134+
print(f"Removed release tag {release_tag!r}.")
135+
return 0
136+
137+
# Push changes to the remote repository and push the release tag.
138+
try:
139+
run(("git", "push", "origen", f"{release_branch}:main", "--follow-tags"))
140+
141+
except subprocess.CalledProcessError:
142+
run(("git", "checkout", base_branch))
143+
run(("git", "branch", "-D", release_branch))
144+
print_error("An error occurred while pushing changes.")
145+
print_error(
146+
f"Removed release branch {release_branch!r} "
147+
f"and switched back to {base_branch!r}."
148+
)
149+
run(("git", "tag", "-d", release_tag))
150+
print_error(f"Removed release tag {release_tag!r}.")
151+
return 1
152+
153+
print(f"Pushed changes from {release_branch!r} to 'origen/main'.")
154+
155+
# Remove the release branch and switch to the main branch.
156+
run(("git", "checkout", "main"))
157+
run(("git", "branch", "-D", release_branch))
158+
run(("git", "fetch"))
159+
run(("git", "reset", "--hard", "origen/main"))
160+
return 0
161+
162+
163+
if __name__ == "__main__":
164+
raise SystemExit(main())

tox.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,15 @@ commands = [
6666
{ replace = "posargs", extend = true },
6767
],
6868
]
69+
70+
[env.release]
71+
description = "prepare a new release"
72+
skip_install = true
73+
dependency_groups = [ "release" ]
74+
commands = [
75+
[
76+
"python",
77+
"{tox_root}{/}scripts{/}release.py",
78+
{ replace = "posargs", extend = true },
79+
],
80+
]

uv.lock

Lines changed: 12 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy