Skip to content

Commit e77b370

Browse files
committed
chore: update demo to the latest cookiecutter-robust-python
1 parent e9c2ad4 commit e77b370

File tree

9 files changed

+172
-53
lines changed

9 files changed

+172
-53
lines changed

.cookiecutter.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"_commit": "dab1f8da6cb6be90a50db1aafb4411ec61fbcb2c",
2+
"_commit": "34a57b81ff4263362669776636b30a8d051687a3",
33
"_template": "C:\\Users\\56kyl\\source\\repos\\cookiecutter-robust-python",
44
"add_rust_extension": false,
55
"author": "Kyle Oliver",

.cruft.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"template": "C:\\Users\\56kyl\\source\\repos\\cookiecutter-robust-python",
3-
"commit": "dab1f8da6cb6be90a50db1aafb4411ec61fbcb2c",
3+
"commit": "34a57b81ff4263362669776636b30a8d051687a3",
44
"checkout": null,
55
"context": {
66
"cookiecutter": {
@@ -18,7 +18,7 @@
1818
"license": "MIT",
1919
"development_status": "Development Status :: 1 - Planning",
2020
"_template": "C:\\Users\\56kyl\\source\\repos\\cookiecutter-robust-python",
21-
"_commit": "dab1f8da6cb6be90a50db1aafb4411ec61fbcb2c"
21+
"_commit": "34a57b81ff4263362669776636b30a8d051687a3"
2222
}
2323
},
2424
"directory": null

.github/workflows/bump-version.yml

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ name: Bump version
33
on:
44
push:
55
branches:
6-
- master
7-
- main
6+
- "release/*"
87

98
jobs:
109
bump-version:
@@ -15,17 +14,9 @@ jobs:
1514
- name: Check out
1615
uses: actions/checkout@v4
1716
with:
18-
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
17+
token: ${{ secrets.GITHUB_TOKEN }}
1918
fetch-depth: 0
2019
- name: Create bump and changelog
2120
uses: commitizen-tools/commitizen-action@master
2221
with:
23-
github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
24-
changelog_increment_filename: body.md
25-
- name: Release
26-
uses: softprops/action-gh-release@v1
27-
with:
28-
body_path: "body.md"
29-
tag_name: ${{ env.REVISION }}
30-
env:
31-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22+
github_token: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: release-github.yml
2+
on:
3+
4+
5+
jobs:
6+
generate-release-notes:
7+
if: "startsWith(github.event.head_commit.message, 'bump:')"
8+
runs-on: ubuntu-latest
9+
name: "Generate Release Notes"
10+
steps:
11+
- name: Create Release Notes
12+
uses: commitizen-tools/commitizen-action@master
13+
with:
14+
github_token: ${{ secrets.GITHUB_TOKEN }}
15+
changelog: "false"
16+
dry_run: "true"
17+
changelog_increment_filename: body.md
18+
- name: Release
19+
uses: softprops/action-gh-release@v1
20+
with:
21+
body_path: "body.md"
22+
tag_name: ${{ env.REVISION }}
23+
env:
24+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/release-python.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,16 @@ jobs:
109109
id: get_tag
110110
run: echo "tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT
111111

112+
- name: Generate Release Notes
113+
run: |
114+
if [ -z "${{ steps.previous_tag.outputs.previous }}" ]; then
115+
echo "No previous tag found: generating changelog for all commits."
116+
cz changelog --dry-run > RELEASE_NOTES.md
117+
else
118+
echo "Previous tag found: generating changelog diff."
119+
cz changelog --dry-run --rev-range ${{ steps.previous_tag.outputs.previous }}..${GITHUB_REF_NAME} > RELEASE_NOTES.md
120+
fi
121+
112122
- name: Create GitHub Release
113123
uses: softprops/action-gh-release@v2
114124
with:

noxfile.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,15 @@ def build_container(session: Session) -> None:
193193
session.log(f"Container image {project_image_name}:latest built locally.")
194194

195195

196-
@nox.session(python=None, name="prepare-release", tags=[RELEASE])
197-
def prepare_release(session: Session) -> None:
196+
@nox.session(python=None, name="seutp-release", tags=[RELEASE])
197+
def setup_release(session: Session) -> None:
198198
"""Prepares a release by creating a release branch and bumping the version.
199199
200-
Does not commit or push the release branch. Additionally, does not tag the release.
200+
Additionally, creates the initial bump commit but doesn't push it.
201201
"""
202-
session.log("Preparing release...")
202+
session.log("Setting up release...")
203203

204-
session.run("python", SCRIPTS_FOLDER / "prepare-release.py", external=True)
204+
session.run("python", SCRIPTS_FOLDER / "setup-release.py", external=True)
205205

206206

207207
@nox.session(python=None, tags=[RELEASE])

scripts/bump-version.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""Script responsible for bumping the version of the robust-python-demo package."""
2+
3+
import argparse
4+
5+
from util import bump_version
6+
7+
8+
def main() -> None:
9+
"""Parses args and passes through to bump_version."""
10+
parser: argparse.ArgumentParser = get_parser()
11+
args: argparse.Namespace = parser.parse_args()
12+
bump_version(increment=args.increment)
13+
14+
15+
def get_parser() -> argparse.ArgumentParser:
16+
"""Creates the argument parser for prepare-release."""
17+
parser: argparse.ArgumentParser = argparse.ArgumentParser(
18+
prog="bump-version", usage="python ./scripts/bump-version.py patch"
19+
)
20+
parser.add_argument(
21+
"increment",
22+
type=str,
23+
help="Increment type to use when preparing the release.",
24+
choices=["MAJOR", "MINOR", "PATCH", "PRERELEASE"],
25+
)
26+
return parser
27+
28+
29+
if __name__ == "__main__":
30+
main()
Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,22 @@
11
"""Script responsible for preparing a release of the robust-python-demo package."""
22

33
import argparse
4-
import re
5-
import shutil
64
import subprocess
7-
from pathlib import Path
8-
from re import Match
9-
from typing import Literal
105
from typing import Optional
11-
from typing import Pattern
12-
from typing import TypeAlias
13-
146

7+
from util import bump_version
158
from util import check_dependencies
16-
from util import remove_readonly
9+
from util import create_release_branch
10+
from util import get_package_version
11+
from util import get_bumped_package_version
1712
from util import REPO_FOLDER
1813

1914

20-
Increment: TypeAlias = Literal["major", "minor", "patch", "prerelease"]
21-
CZ_PATTERN: Pattern[str] = re.compile(r"bump: version (?P<current_version>.*?) → (?P<new_version>.*?)")
22-
23-
2415
def main() -> None:
25-
"""Parses args and passes through to prepare_release."""
16+
"""Parses args and passes through to setup_release."""
2617
parser: argparse.ArgumentParser = get_parser()
2718
args: argparse.Namespace = parser.parse_args()
28-
prepare_release(path=args.path, python_version=args.python_version)
19+
setup_release(increment=args.increment)
2920

3021

3122
def get_parser() -> argparse.ArgumentParser:
@@ -42,39 +33,27 @@ def get_parser() -> argparse.ArgumentParser:
4233
return parser
4334

4435

45-
def prepare_release(increment: Optional[str] = None) -> None:
36+
def setup_release(increment: Optional[str] = None) -> None:
4637
"""Prepares a release of the robust-python-demo package.
4738
4839
Sets up a release branch from the branch develop, bumps the version, and creates a release commit. Does not tag the
4940
release or push any changes.
5041
"""
51-
dry_run_cmd: list[str] = ["uvx", "cz", "bump", "--dry-run", "--yes"]
52-
bump_cmd: list[str] = ["uvx", "cz", "bump", "--yes", "--files-only", "--changelog"]
53-
if increment is not None:
54-
dry_run_cmd.extend(["--increment", increment])
55-
bump_cmd.extend(["--increment", increment])
42+
check_dependencies(path=REPO_FOLDER, dependencies=["git", "cz"])
5643

57-
result: subprocess.CompletedProcess = subprocess.run(dry_run_cmd, cwd=REPO_FOLDER, capture_output=True)
58-
match: Match = re.match(CZ_PATTERN, result.stdout)
59-
current_version: str = match.group("current_version")
60-
new_version: str = match.group("new_version")
44+
current_version: str = get_package_version()
45+
new_version: str = get_bumped_package_version(increment=increment)
46+
create_release_branch(new_version=new_version)
47+
bump_version(increment=increment)
6148

6249
commands: list[list[str]] = [
63-
["git", "status", "--porcelain"],
64-
["git", "branch", "-b", f"release/{new_version}", "develop"],
65-
["git", "checkout", f"release/{new_version}"],
66-
bump_cmd,
6750
["git", "add", "."],
6851
["git", "commit", "-m", f"bump: version {current_version}{new_version}"]
6952
]
7053

71-
check_dependencies(path=REPO_FOLDER, dependencies=["git", "cz"])
72-
7354
for command in commands:
7455
subprocess.run(command, cwd=REPO_FOLDER, capture_output=True, check=True)
7556

7657

7758
if __name__ == "__main__":
7859
main()
79-
80-

scripts/util.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@
66
from pathlib import Path
77
from typing import Any
88
from typing import Callable
9+
from typing import Literal
10+
from typing import Optional
11+
from typing import TypeAlias
912

1013

1114
REPO_FOLDER: Path = Path(__file__).resolve().parent.parent
1215

16+
Increment: TypeAlias = Literal["MAJOR", "MINOR", "PATCH", "PRERELEASE"]
17+
1318

1419
class MissingDependencyError(Exception):
1520
"""Exception raised when a depedency is missing from the system running setup-repo."""
@@ -52,3 +57,83 @@ def remove_readonly(func: Callable[[str], Any], path: str, _: Any) -> None:
5257
"""
5358
Path(path).chmod(stat.S_IWRITE)
5459
func(path)
60+
61+
62+
def get_package_version() -> str:
63+
"""Gets the package version."""
64+
result: subprocess.CompletedProcess = subprocess.run(
65+
["uvx", "version", "-p"],
66+
cwd=REPO_FOLDER,
67+
capture_output=True
68+
)
69+
return result.stdout.decode("utf-8").strip()
70+
71+
72+
def get_bumped_package_version(increment: Optional[Increment] = None) -> str:
73+
"""Gets the bumped package version."""
74+
args: list[str] = ["uvx", "cz", "bump", "--get-next", "--yes", "--dry-run"]
75+
if increment is not None:
76+
args.extend(["--increment", increment])
77+
result: subprocess.CompletedProcess = subprocess.run(args, cwd=REPO_FOLDER, capture_output=True)
78+
return result.stdout.decode("utf-8").strip()
79+
80+
81+
def create_release_branch(new_version: str) -> None:
82+
"""Creates a release branch."""
83+
commands: list[list[str]] = [
84+
["git", "status", "--porcelain"],
85+
["git", "branch", "-b", f"release/{new_version}", "develop"],
86+
["git", "checkout", f"release/{new_version}"],
87+
]
88+
for command in commands:
89+
subprocess.run(command, cwd=REPO_FOLDER, capture_output=True, check=True)
90+
91+
92+
def bump_version(increment: Optional[Increment] = None) -> None:
93+
"""Bumps the package version."""
94+
bump_cmd: list[str] = ["uvx", "cz", "bump", "--yes", "--files-only", "--changelog"]
95+
if increment is not None:
96+
bump_cmd.extend(["--increment", increment])
97+
subprocess.run(bump_cmd, cwd=REPO_FOLDER, check=True)
98+
99+
100+
def get_latest_tag() -> Optional[str]:
101+
"""Gets the latest git tag."""
102+
sort_tags: list[str] = ["git", "tag", "--sort=-creatordate"]
103+
find_last: list[str] = ["grep", "-v", '"${GITHUB_REF_NAME}"']
104+
echo_none: list[str] = ["echo", "''"]
105+
result: subprocess.CompletedProcess = subprocess.run(
106+
[*sort_tags, "|", *find_last, "|", "tail", "-n1", "||", *echo_none],
107+
cwd=REPO_FOLDER,
108+
capture_output=True
109+
)
110+
tag: str = result.stdout.decode("utf-8").strip()
111+
if tag == "":
112+
return None
113+
return tag
114+
115+
116+
def get_latest_release_notes() -> None:
117+
"""Gets the release notes.
118+
119+
Assumes the latest_tag hasn't been applied yet.
120+
"""
121+
latest_tag: Optional[str] = get_latest_tag()
122+
latest_version: str = get_package_version()
123+
if latest_tag == latest_version:
124+
raise ValueError(
125+
"The latest tag and version are the same. Please ensure the release notes are taken before tagging."
126+
)
127+
rev_range: str = latest_version if latest_tag is None else f"{latest_tag}..{latest_version}"
128+
129+
result: subprocess.CompletedProcess = subprocess.run(
130+
["uvx", "cz", "changelog", rev_range, "--dry-run"],
131+
cwd=REPO_FOLDER,
132+
check=True
133+
)
134+
return result.stdout.decode("utf-8")
135+
136+
137+
def tag_release() -> None:
138+
"""Tags the release using commitizen bump with tag only."""
139+
subprocess.run(["uvx", "cz", "bump", "--tag-only", "--yes"], cwd=REPO_FOLDER, check=True)

0 commit comments

Comments
 (0)