Skip to content

Commit 482a979

Browse files
committed
add bumpversion script in commands.py for updating version numbers
1 parent 754dfe7 commit 482a979

2 files changed

Lines changed: 124 additions & 12 deletions

File tree

RELEASE.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ This is the release process for releasing plotly.py version `X.Y.Z`, including c
77

88
### Finalize changelog
99

10-
Review the contents of `CHANGELOG.md`. We try to follow
10+
Review the contents of `CHANGELOG.md` under the **Unreleased** header. We try to follow
1111
the [keepachangelog](https://keepachangelog.com/en/1.0.0/) guidelines.
12-
Make sure the changelog includes the version being published at the top, along
13-
with the expected publication date.
12+
13+
**Note: You don't need to update the header itself with the new version number,
14+
as that will be done automatically as part of the next step.**
1415

1516
Use the `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, and `Security`
1617
labels for all changes to plotly.py. If the version of plotly.js has
@@ -22,18 +23,24 @@ a link to the plotly.js CHANGELOG.
2223

2324
**Create a release branch `git checkout -b release-X.Y.Z` _from the tip of `origin/main`_.**
2425

25-
- Manually update the versions to `X.Y.Z` in the files specified below:
26+
- Ensure that you have `npm` and `uv` installed in your environment
27+
28+
- Run the command `python commands.py bumpversion X.Y.Z`, which will update the version to X.Y.Z in the following places
2629
- `pyproject.toml`
27-
- update version
30+
- `uv.lock`
2831
- `js/package.json`
29-
- update version (`"version"` key at top of file)
30-
- `CHANGELOG.md`
31-
- update version and release date
32-
- finalize changelog entries according to instructions above
32+
- `js/package-lock.json`
33+
- `CHANGELOG.md` (Adds a new header for X.Y.Z above the unreleased items)
3334
- `CITATION.cff`
34-
- update version and release date
35-
- Run `uv lock` to update the version number in the `uv.lock` file (do not update manually)
36-
- Commit and push your changes to the release branch:
35+
36+
- Run `git diff` and ensure the above files were all updated correctly.
37+
- Note: The current date is used as the release date in `CHANGELOG.md` and `CITATION.cff`. If you want to use a different date, edit these files manually afterward.
38+
- If the bumpversion command failed for any reason, you can update the versions yourself by doing the following:
39+
- Manually update the version number (and release date, as needed) in `pyproject.toml`, `CHANGELOG.md` and `CITATION.cff`
40+
- Run `npm version X.Y.Z` to update `js/package.json` and `js/package-lock.json`
41+
- Run `uv lock` to update `uv.lock`
42+
43+
- Commit and push the changed files to the release branch:
3744
```sh
3845
$ git add -u
3946
$ git commit -m "version changes for vX.Y.Z"

commands.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
import json
66
import os
77
import platform
8+
import re
89
import requests
910
import shutil
11+
import subprocess
1012
from subprocess import check_call
1113
import sys
1214
import time
@@ -296,6 +298,102 @@ def update_plotlyjs_dev(args, outdir):
296298
perform_codegen(outdir)
297299

298300

301+
def bump_version_pyproject_toml(new_version):
302+
"""Bump the version in pyproject.toml to new_version"""
303+
304+
pyproject_toml_path = "pyproject.toml"
305+
pattern = r'(^\s*version\s*=\s*")([\w.]+)"(\s*$)'
306+
with open(pyproject_toml_path, "r") as f:
307+
content = f.read()
308+
new_content = re.sub(
309+
pattern,
310+
rf'\g<1>{new_version}"\g<3>',
311+
content,
312+
count=1, # replace only the first match
313+
flags=re.MULTILINE,
314+
)
315+
with open(pyproject_toml_path, "w") as f:
316+
f.write(new_content)
317+
318+
# Run `uv lock` to update the version number in the `uv.lock` file (do not update manually)
319+
subprocess.run(["uv", "lock"], check=True)
320+
321+
print(f"Updated version in {pyproject_toml_path} to {new_version}, and updated uv lockfile")
322+
323+
324+
def bump_version_package_json(new_version):
325+
"""Bump the version in package.json to new_version"""
326+
js_dir = "js"
327+
subprocess.run(
328+
["npm", "version", new_version, "--no-git-tag-version", "--allow-same-version"],
329+
cwd=js_dir,
330+
check=True,
331+
)
332+
print(
333+
f"Updated version in {js_dir}/package.json and {js_dir}/package-lock.json to {new_version}"
334+
)
335+
336+
337+
def bump_version_citation_cff(new_version, new_date):
338+
"""Bump the version in CITATION.cff to new_version and date-released to new_date"""
339+
citation_cff_path = "CITATION.cff"
340+
pattern_version = r'(^\s*version\s*:\s*)([\w.]+)(\s*$)'
341+
pattern_date = r'(^\s*date-released\s*:\s*)([0-9\-]+)(\s*$)'
342+
343+
with open(citation_cff_path, "r") as f:
344+
content = f.read()
345+
new_content = re.sub(
346+
pattern_version,
347+
rf'\g<1>{new_version}\g<3>',
348+
content,
349+
count=1, # replace only the first match
350+
flags=re.MULTILINE,
351+
)
352+
new_content = re.sub(
353+
pattern_date,
354+
rf'\g<1>{new_date}\g<3>',
355+
new_content,
356+
count=1, # replace only the first match
357+
flags=re.MULTILINE,
358+
)
359+
with open(citation_cff_path, "w") as f:
360+
f.write(new_content)
361+
print(
362+
f"Updated version in {citation_cff_path} to {new_version} and date-released to {new_date}"
363+
)
364+
365+
def bump_version_changelog_md(new_version, new_date):
366+
"""Bump the version in CHANGELOG.md to new_version and date to new_date"""
367+
changelog_md_path = "CHANGELOG.md"
368+
pattern = r'(^\s*##\s*Unreleased\s*$)'
369+
new_header = f"\n\n## [{new_version}] - {new_date}\n"
370+
with open(changelog_md_path, "r") as f:
371+
content = f.read()
372+
new_content = re.sub(
373+
pattern,
374+
rf'\g<1>{new_header}',
375+
content,
376+
count=1, # replace only the first match
377+
flags=re.MULTILINE,
378+
)
379+
with open(changelog_md_path, "w") as f:
380+
f.write(new_content)
381+
print(f"Updated version in {changelog_md_path} to {new_version}")
382+
383+
384+
def bump_version(args):
385+
"""Bump the version of plotly.py everywhere it needs to be updated."""
386+
new_version = args.version
387+
new_date = time.strftime("%Y-%m-%d")
388+
389+
# bump_version_citation_cff(new_version, new_date)
390+
# bump_version_changelog_md(new_version, new_date)
391+
# bump_version_package_json(new_version)
392+
# Do this one last since it's the most visible,
393+
# so that if one of the above commands fails it will be easier to notice
394+
bump_version_pyproject_toml(new_version)
395+
396+
299397
def make_parser():
300398
"""Make argument parser."""
301399

@@ -322,6 +420,10 @@ def make_parser():
322420

323421
subparsers.add_parser("updateplotlyjs", help="update plotly.js")
324422

423+
p_bump_version = subparsers.add_parser("bumpversion", help="bump plotly.py version")
424+
# Add a positional argument for the version
425+
p_bump_version.add_argument("version", help="version number")
426+
325427
return parser
326428

327429

@@ -356,6 +458,9 @@ def main():
356458
print(version)
357459
update_plotlyjs(version, outdir)
358460

461+
elif args.cmd == "bumpversion":
462+
bump_version(args)
463+
359464
elif args.cmd is None:
360465
parser.print_help()
361466
sys.exit(1)

0 commit comments

Comments
 (0)