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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
"""Automate the release draft + PR creation process."""
import re
from pathlib import Path
from subprocess import CalledProcessError
import requests
from release.shared import (
GITHUB_TOKEN,
HISTORY_FILE,
REPO,
run_command,
)
ROOT_DIR = Path(__file__).parent.parent
HISTORY_RELEASE_HEAD_REGEX = r'^## v(\d+\.\d+\.\d+[a-zA-Z0-9]*)\s'
def get_latest_version_from_changelog() -> str:
"""Get the most recently listed version from the changelog."""
with open(ROOT_DIR / HISTORY_FILE, encoding='utf8') as f:
for line in f:
match = re.match(HISTORY_RELEASE_HEAD_REGEX, line)
if match:
return match.group(1)
raise ValueError('Latest version not found in changelog')
def get_latest_release_notes_from_changelog() -> str:
"""Get the release notes for the latest version from the changelog."""
with open(ROOT_DIR / HISTORY_FILE, encoding='utf8') as f:
for line in f:
match = re.match(HISTORY_RELEASE_HEAD_REGEX, line)
if match:
break
else:
raise ValueError('Latest version not found in changelog')
release_notes_li: list[str] = []
for line in f:
if re.match(HISTORY_RELEASE_HEAD_REGEX, line):
break
release_notes_li.append(line)
return ''.join(release_notes_li)
def commit_and_push_changes(rl_version: str) -> None:
"""Commit and push changes to a new branch."""
branch_name = f'release/v{rl_version}'
run_command('git', 'checkout', '-b', branch_name)
run_command('git', 'add', '-A')
try:
run_command('git', 'commit', '-m', f'Bump version to v{rl_version}')
except CalledProcessError as e:
print('No changes related to version bump. Are you sure that you have run prepare.py?')
raise e
run_command('git', 'push', 'origin', branch_name)
def open_pull_request(rl_version: str):
"""Open a pull request on GitHub."""
url = f'https://api.github.com/repos/{REPO}/pulls'
headers = {'Authorization': f'token {GITHUB_TOKEN}'}
data = {
'title': f'Release v{rl_version}',
'head': f'release/v{rl_version}',
'base': 'main',
'body': f'Bumping version to v{rl_version}.',
}
response = requests.post(url, json=data, headers=headers, timeout=10)
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
print(f'HTTP error occurred: {e}')
print(f'Response content: {response.content.decode()}')
raise e
return response.json()['html_url']
def create_version_tag(rl_version: str):
"""Create a version tag."""
run_command('git', 'tag', f'v{rl_version}')
run_command('git', 'push', 'origin', f'v{rl_version}')
def create_github_release(new_version: str, notes: str):
"""Create a new release on GitHub."""
url = f'https://api.github.com/repos/{REPO}/releases'
data = {
'tag_name': f'v{new_version}',
'name': f'v{new_version}',
'body': notes,
'draft': True,
}
response = requests.post(
url,
headers={
'Authorization': f'Bearer {GITHUB_TOKEN}',
'Accept': 'application/vnd.github+json',
},
json=data,
timeout=10,
)
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
print(f'HTTP error occurred: {e}')
print(f'Response content: {response.content.decode()}')
raise e
def create_github_release_draft(rl_version: str, rl_release_notes: str):
"""Create a GitHub release draft."""
url = f'https://api.github.com/repos/{REPO}/releases'
headers = {'Authorization': f'token {GITHUB_TOKEN}'}
data = {
'tag_name': f'v{rl_version}',
'name': f'v{rl_version}',
'body': rl_release_notes,
'draft': True,
'prerelease': False,
}
response = requests.post(url, json=data, headers=headers, timeout=10)
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
print(f'HTTP error occurred: {e}')
print(f'Response content: {response.content.decode()}')
raise e
release_url = response.json()['html_url']
# Publishing happens in the edit page
edit_url = release_url.replace('/releases/tag/', '/releases/edit/')
return edit_url
if __name__ == '__main__':
version = get_latest_version_from_changelog()
release_notes = get_latest_release_notes_from_changelog()
commit_and_push_changes(version)
pr_url = open_pull_request(version)
print(f'Opened PR: {pr_url}')
create_version_tag(version)
draft_url = create_github_release_draft(version, release_notes)
print(f'Release draft created: {draft_url}')
print(f'SUCCESS: Completed release process for v{version}')
|