-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e0ae6ee
commit 19f77e6
Showing
7 changed files
with
474 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#!/usr/bin/env python3 | ||
import glob | ||
import re | ||
import subprocess | ||
|
||
|
||
def get_version() -> str: | ||
"""Return the current version number, based on the _version.py file.""" | ||
[version_file] = glob.glob("climada*/_version.py") | ||
with open(version_file) as vf: | ||
content = vf.read() | ||
regex = r'^__version__\s*=\s*[\'\"](.*)[\'\"]\s*$' | ||
mtch = re.match(regex, content) | ||
return mtch.group(1) | ||
|
||
|
||
def make_release(): | ||
"""run `gh release create vX.Y.Z""" | ||
version_number = get_version() | ||
subprocess.run( | ||
["gh", "release", "create", "--generate-notes", f"v{version_number}"], | ||
check=True, | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
make_release() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
#!/usr/bin/env python3 | ||
import glob | ||
import json | ||
import re | ||
import subprocess | ||
import time | ||
|
||
|
||
def get_last_version() -> str: | ||
"""Return the version number of the last release.""" | ||
json_string = ( | ||
subprocess.run( | ||
["gh", "release", "view", "--json", "tagName"], | ||
check=True, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
) | ||
.stdout.decode("utf8") | ||
.strip() | ||
) | ||
|
||
return json.loads(json_string)["tagName"] | ||
|
||
|
||
def bump_version_number(version_number: str, level: str) -> str: | ||
"""Return a copy of `version_number` with one level number incremented.""" | ||
major, minor, patch = version_number.split(".") | ||
if level == "major": | ||
major = str(int(major)+1) | ||
elif level == "minor": | ||
minor = str(int(minor)+1) | ||
elif level == "patch": | ||
patch = str(int(patch)+1) | ||
else: | ||
raise ValueError(f"level should be 'major', 'minor' or 'patch', not {level}") | ||
return ".".join([major, minor, patch]) | ||
|
||
|
||
def update_readme(nvn): | ||
"""align doc/misc/README.md with ./README.md but remove the non-markdown header lines from """ | ||
with open("README.md", 'r') as rmin: | ||
lines = [line for line in rmin.readlines() if not line.startswith('[![')] | ||
while not lines[0].strip(): | ||
lines = lines[1:] | ||
with open("doc/misc/README.md", 'w') as rmout: | ||
rmout.writelines(lines) | ||
return GitFile('doc/misc/README.md') | ||
|
||
|
||
def update_changelog(nvn): | ||
"""Rename the "Unreleased" section, remove unused subsections and the code-freeze date, | ||
set the release date to today""" | ||
r = [] | ||
crn = None | ||
cr = [] | ||
ctn = None | ||
ct = [] | ||
with open("CHANGELOG.md", 'r') as cl: | ||
for line in cl.readlines(): | ||
if line.startswith('#'): | ||
if line.startswith('### '): | ||
if ct: | ||
cr.append((ctn, ct)) | ||
ctn = line[4:].strip() | ||
ct = [] | ||
#print("tag:", ctn) | ||
elif line.startswith('## '): | ||
if ct: | ||
cr.append((ctn, ct)) | ||
if cr: | ||
r.append((crn, cr)) | ||
crn = line[3:].strip() | ||
cr = [] | ||
ctn = None | ||
ct = [] | ||
#print("release:", crn) | ||
else: | ||
ct.append(line) | ||
if ct: | ||
cr.append((ctn, ct)) | ||
if cr: | ||
r.append((crn, cr)) | ||
|
||
with open("CHANGELOG.md", 'w') as cl: | ||
cl.write("# Changelog\n\n") | ||
for crn, cr in r: | ||
if crn: | ||
if crn.lower() == "unreleased": | ||
crn = nvn | ||
cl.write(f"## {crn}\n") | ||
for ctn, ct in cr: | ||
if any(ln.strip() for ln in ct): | ||
if ctn: | ||
cl.write(f"### {ctn}\n") | ||
lines = [ln.strip() for ln in ct if "code freeze date: " not in ln.lower()] | ||
if not ctn and crn.lower() == nvn: | ||
print("setting date") | ||
for i, line in enumerate(lines): | ||
if "release date: " in line.lower(): | ||
today = time.strftime("%Y-%m-%d") | ||
lines[i] = f"Release date: {today}" | ||
cl.write("\n".join(lines).replace("\n\n", "\n")) | ||
cl.write("\n") | ||
return GitFile('CHANGELOG.md') | ||
|
||
|
||
def update_version(nvn): | ||
"""Update the _version.py file""" | ||
[file_with_version] = glob.glob("climada*/_version.py") | ||
regex = r'(^__version__\s*=\s*[\'\"]).*([\'\"]\s*$)' | ||
return update_file(file_with_version, regex, nvn) | ||
|
||
|
||
def update_setup(new_version_number): | ||
"""Update the setup.py file""" | ||
file_with_version = "setup.py" | ||
regex = r'(^\s+version\s*=\s*[\'\"]).*([\'\"]\s*,\s*$)' | ||
return update_file(file_with_version, regex, new_version_number) | ||
|
||
|
||
def update_file(file_with_version, regex, new_version_number): | ||
"""Replace the version number(s) in a file, based on a rgular expression.""" | ||
with open(file_with_version, 'r') as curf: | ||
lines = curf.readlines() | ||
successfully_updated = False | ||
for i, line in enumerate(lines): | ||
m = re.match(regex, line) | ||
if m: | ||
lines[i] = f"{m.group(1)}{new_version_number}{m.group(2)}" | ||
successfully_updated = True | ||
if not successfully_updated: | ||
raise Exception(f"cannot determine version of {file_with_version}") | ||
with open(file_with_version, 'w') as newf: | ||
for line in lines: | ||
newf.write(line) | ||
return GitFile(file_with_version) | ||
|
||
|
||
class GitFile(): | ||
"""Helper class for `git add`.""" | ||
def __init__(self, path): | ||
self.path = path | ||
|
||
def gitadd(self): | ||
"""run `git add`""" | ||
answer = subprocess.run( | ||
["git", "add", self.path], | ||
check=True, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
).stdout.decode("utf8") | ||
#print(answer) | ||
|
||
|
||
class Git(): | ||
"""Helper class for `git commit`.""" | ||
def __init__(self): | ||
_gitname = subprocess.run( | ||
["git", "config", "--global", "user.name", "'climada'"], | ||
check=True, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
).stdout.decode("utf8") | ||
_gitemail = subprocess.run( | ||
["git", "config", "--global", "user.email", "'test.climada@gmail.com'"], | ||
check=True, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
).stdout.decode("utf8") | ||
|
||
def commit(self, new_version): | ||
"""run `git commit`.""" | ||
try: | ||
_gitcommit = subprocess.run( | ||
["git", "commit", "-m", f"'Automated update v{new_version}'"], | ||
check=True, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
).stdout.decode("utf8") | ||
_gitpush = subprocess.run( | ||
["git", "push"], | ||
check=True, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
).stdout.decode("utf8") | ||
except subprocess.CalledProcessError as err: | ||
message = err.stdout.decode("utf8") | ||
print("message:", message) | ||
if ("nothing to commit" in message): | ||
print("repo already up to date with new version number") | ||
else: | ||
raise Exception(f"failed to run: {message}") from err | ||
|
||
|
||
def prepare_new_release(level): | ||
"""Prepare files for a new release on GitHub.""" | ||
try: | ||
last_version_number = get_last_version().strip("v") | ||
except subprocess.CalledProcessError as err: | ||
if "release not found" in err.stderr.decode("utf8"): | ||
# The project doesn't have any releases yet. | ||
last_version_number = "0.0.0" | ||
else: | ||
raise | ||
new_version_number = bump_version_number(last_version_number, level) | ||
|
||
update_setup(new_version_number).gitadd() | ||
update_version(new_version_number).gitadd() | ||
update_changelog(new_version_number).gitadd() | ||
update_readme(new_version_number).gitadd() | ||
|
||
Git().commit(new_version_number) | ||
|
||
|
||
if __name__ == "__main__": | ||
from sys import argv | ||
try: | ||
level = argv[1] | ||
except IndexError: | ||
level = "patch" | ||
prepare_new_release(level) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
#!/usr/bin/env python3 | ||
import glob | ||
import json | ||
import re | ||
import subprocess | ||
|
||
|
||
def get_last_version() -> str: | ||
"""Return the version number of the last release.""" | ||
json_string = ( | ||
subprocess.run( | ||
["gh", "release", "view", "--json", "tagName"], | ||
check=True, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE, | ||
) | ||
.stdout.decode("utf8") | ||
.strip() | ||
) | ||
|
||
return json.loads(json_string)["tagName"] | ||
|
||
|
||
def update_changelog(): | ||
"""Insert a vanilla "Unreleased" section on top.""" | ||
with open("CHANGELOG.md", 'r') as cl: | ||
lines = cl.readlines() | ||
|
||
if "## Unreleased" in lines: | ||
return | ||
|
||
with open("CHANGELOG.md", 'w') as cl: | ||
cl.write("""# Changelog | ||
## Unreleased | ||
Release date: YYYY-MM-DD | ||
Code freeze date: YYYY-MM-DD | ||
### Description | ||
### Dependency Changes | ||
### Added | ||
### Changed | ||
### Fixed | ||
### Deprecated | ||
### Removed | ||
""") | ||
cl.writelines(lines[2:]) | ||
|
||
|
||
def update_version(nvn): | ||
"""Update the _version.py file""" | ||
[file_with_version] = glob.glob("climada*/_version.py") | ||
regex = r'(^__version__\s*=\s*[\'\"]).*([\'\"]\s*$)' | ||
return update_file(file_with_version, regex, nvn) | ||
|
||
|
||
def update_setup(new_version_number): | ||
"""Update the setup.py file""" | ||
file_with_version = "setup.py" | ||
regex = r'(^\s+version\s*=\s*[\'\"]).*([\'\"]\s*,\s*$)' | ||
return update_file(file_with_version, regex, new_version_number) | ||
|
||
|
||
def update_file(file_with_version, regex, new_version_number): | ||
"""Replace the version number(s) in a file, based on a rgular expression.""" | ||
with open(file_with_version, 'r') as curf: | ||
lines = curf.readlines() | ||
successfully_updated = False | ||
for i, line in enumerate(lines): | ||
m = re.match(regex, line) | ||
if m: | ||
lines[i] = f"{m.group(1)}{new_version_number}{m.group(2)}" | ||
successfully_updated = True | ||
if not successfully_updated: | ||
raise Exception(f"cannot determine version of {file_with_version}") | ||
with open(file_with_version, 'w') as newf: | ||
for line in lines: | ||
newf.write(line) | ||
|
||
|
||
def setup_devbranch(): | ||
"""Adjust files after a release was published, i.e., | ||
apply the canonical deviations from main in develop. | ||
Just changes files, all `git` commands are in the setup_devbranch.sh file. | ||
""" | ||
main_version = get_last_version().strip('v') | ||
|
||
dev_version = f"{main_version}-dev" | ||
|
||
update_setup(dev_version) | ||
update_version(dev_version) | ||
update_changelog() | ||
|
||
print(f"v{dev_version}") | ||
|
||
|
||
if __name__ == "__main__": | ||
setup_devbranch() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#!/usr/bin/bash | ||
|
||
set -e | ||
|
||
git config --global user.name 'climada' | ||
git config --global user.email 'test.climada@gmail.com' | ||
|
||
git fetch --unshallow || echo cannot \"git fetch --unshallow \" | ||
git checkout develop | ||
git pull | ||
|
||
git checkout origin/main \ | ||
setup.py \ | ||
doc/misc/README.md \ | ||
CHANGELOG.md \ | ||
*/_version.py | ||
|
||
release=`python .github/scripts/setup_devbranch.py` | ||
|
||
git add \ | ||
setup.py \ | ||
doc/misc/README.md \ | ||
CHANGELOG.md \ | ||
*/_version.py | ||
|
||
git commit -m "setup develop branch for $release" | ||
|
||
git push || echo cannot \"git push\" | ||
git checkout main |
Oops, something went wrong.