1*61046927SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*61046927SAndroid Build Coastguard Worker# Copyright © 2019-2020 Intel Corporation 3*61046927SAndroid Build Coastguard Worker 4*61046927SAndroid Build Coastguard Worker# Permission is hereby granted, free of charge, to any person obtaining a copy 5*61046927SAndroid Build Coastguard Worker# of this software and associated documentation files (the "Software"), to deal 6*61046927SAndroid Build Coastguard Worker# in the Software without restriction, including without limitation the rights 7*61046927SAndroid Build Coastguard Worker# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8*61046927SAndroid Build Coastguard Worker# copies of the Software, and to permit persons to whom the Software is 9*61046927SAndroid Build Coastguard Worker# furnished to do so, subject to the following conditions: 10*61046927SAndroid Build Coastguard Worker 11*61046927SAndroid Build Coastguard Worker# The above copyright notice and this permission notice shall be included in 12*61046927SAndroid Build Coastguard Worker# all copies or substantial portions of the Software. 13*61046927SAndroid Build Coastguard Worker 14*61046927SAndroid Build Coastguard Worker# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15*61046927SAndroid Build Coastguard Worker# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16*61046927SAndroid Build Coastguard Worker# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17*61046927SAndroid Build Coastguard Worker# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18*61046927SAndroid Build Coastguard Worker# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19*61046927SAndroid Build Coastguard Worker# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20*61046927SAndroid Build Coastguard Worker# SOFTWARE. 21*61046927SAndroid Build Coastguard Worker 22*61046927SAndroid Build Coastguard Worker"""Generates release notes for a given version of mesa.""" 23*61046927SAndroid Build Coastguard Worker 24*61046927SAndroid Build Coastguard Workerimport asyncio 25*61046927SAndroid Build Coastguard Workerimport datetime 26*61046927SAndroid Build Coastguard Workerimport os 27*61046927SAndroid Build Coastguard Workerimport pathlib 28*61046927SAndroid Build Coastguard Workerimport re 29*61046927SAndroid Build Coastguard Workerimport subprocess 30*61046927SAndroid Build Coastguard Workerimport sys 31*61046927SAndroid Build Coastguard Workerimport textwrap 32*61046927SAndroid Build Coastguard Workerimport typing 33*61046927SAndroid Build Coastguard Workerimport urllib.parse 34*61046927SAndroid Build Coastguard Worker 35*61046927SAndroid Build Coastguard Workerimport aiohttp 36*61046927SAndroid Build Coastguard Workerfrom mako.template import Template 37*61046927SAndroid Build Coastguard Workerfrom mako import exceptions 38*61046927SAndroid Build Coastguard Worker 39*61046927SAndroid Build Coastguard Workerimport docutils.utils 40*61046927SAndroid Build Coastguard Workerimport docutils.parsers.rst.states as states 41*61046927SAndroid Build Coastguard Worker 42*61046927SAndroid Build Coastguard WorkerCURRENT_GL_VERSION = '4.6' 43*61046927SAndroid Build Coastguard WorkerCURRENT_VK_VERSION = '1.3' 44*61046927SAndroid Build Coastguard Worker 45*61046927SAndroid Build Coastguard WorkerTEMPLATE = Template(textwrap.dedent("""\ 46*61046927SAndroid Build Coastguard Worker ${header} 47*61046927SAndroid Build Coastguard Worker ${header_underline} 48*61046927SAndroid Build Coastguard Worker 49*61046927SAndroid Build Coastguard Worker %if not bugfix: 50*61046927SAndroid Build Coastguard Worker Mesa ${this_version} is a new development release. People who are concerned 51*61046927SAndroid Build Coastguard Worker with stability and reliability should stick with a previous release or 52*61046927SAndroid Build Coastguard Worker wait for Mesa ${this_version[:-1]}1. 53*61046927SAndroid Build Coastguard Worker %else: 54*61046927SAndroid Build Coastguard Worker Mesa ${this_version} is a bug fix release which fixes bugs found since the ${previous_version} release. 55*61046927SAndroid Build Coastguard Worker %endif 56*61046927SAndroid Build Coastguard Worker 57*61046927SAndroid Build Coastguard Worker Mesa ${this_version} implements the OpenGL ${gl_version} API, but the version reported by 58*61046927SAndroid Build Coastguard Worker glGetString(GL_VERSION) or glGetIntegerv(GL_MAJOR_VERSION) / 59*61046927SAndroid Build Coastguard Worker glGetIntegerv(GL_MINOR_VERSION) depends on the particular driver being used. 60*61046927SAndroid Build Coastguard Worker Some drivers don't support all the features required in OpenGL ${gl_version}. OpenGL 61*61046927SAndroid Build Coastguard Worker ${gl_version} is **only** available if requested at context creation. 62*61046927SAndroid Build Coastguard Worker Compatibility contexts may report a lower version depending on each driver. 63*61046927SAndroid Build Coastguard Worker 64*61046927SAndroid Build Coastguard Worker Mesa ${this_version} implements the Vulkan ${vk_version} API, but the version reported by 65*61046927SAndroid Build Coastguard Worker the apiVersion property of the VkPhysicalDeviceProperties struct 66*61046927SAndroid Build Coastguard Worker depends on the particular driver being used. 67*61046927SAndroid Build Coastguard Worker 68*61046927SAndroid Build Coastguard Worker SHA checksums 69*61046927SAndroid Build Coastguard Worker ------------- 70*61046927SAndroid Build Coastguard Worker 71*61046927SAndroid Build Coastguard Worker :: 72*61046927SAndroid Build Coastguard Worker 73*61046927SAndroid Build Coastguard Worker TBD. 74*61046927SAndroid Build Coastguard Worker 75*61046927SAndroid Build Coastguard Worker 76*61046927SAndroid Build Coastguard Worker New features 77*61046927SAndroid Build Coastguard Worker ------------ 78*61046927SAndroid Build Coastguard Worker 79*61046927SAndroid Build Coastguard Worker %for f in features: 80*61046927SAndroid Build Coastguard Worker - ${rst_escape(f)} 81*61046927SAndroid Build Coastguard Worker %endfor 82*61046927SAndroid Build Coastguard Worker 83*61046927SAndroid Build Coastguard Worker 84*61046927SAndroid Build Coastguard Worker Bug fixes 85*61046927SAndroid Build Coastguard Worker --------- 86*61046927SAndroid Build Coastguard Worker 87*61046927SAndroid Build Coastguard Worker %for b in bugs: 88*61046927SAndroid Build Coastguard Worker - ${rst_escape(b)} 89*61046927SAndroid Build Coastguard Worker %endfor 90*61046927SAndroid Build Coastguard Worker 91*61046927SAndroid Build Coastguard Worker 92*61046927SAndroid Build Coastguard Worker Changes 93*61046927SAndroid Build Coastguard Worker ------- 94*61046927SAndroid Build Coastguard Worker %for c, author_line in changes: 95*61046927SAndroid Build Coastguard Worker %if author_line: 96*61046927SAndroid Build Coastguard Worker 97*61046927SAndroid Build Coastguard Worker ${rst_escape(c)} 98*61046927SAndroid Build Coastguard Worker 99*61046927SAndroid Build Coastguard Worker %else: 100*61046927SAndroid Build Coastguard Worker - ${rst_escape(c)} 101*61046927SAndroid Build Coastguard Worker %endif 102*61046927SAndroid Build Coastguard Worker %endfor 103*61046927SAndroid Build Coastguard Worker """)) 104*61046927SAndroid Build Coastguard Worker 105*61046927SAndroid Build Coastguard Worker 106*61046927SAndroid Build Coastguard Worker# copied from https://docutils.sourceforge.io/sandbox/xml2rst/xml2rstlib/markup.py 107*61046927SAndroid Build Coastguard Workerclass Inliner(states.Inliner): 108*61046927SAndroid Build Coastguard Worker """ 109*61046927SAndroid Build Coastguard Worker Recognizer for inline markup. Derive this from the original inline 110*61046927SAndroid Build Coastguard Worker markup parser for best results. 111*61046927SAndroid Build Coastguard Worker """ 112*61046927SAndroid Build Coastguard Worker 113*61046927SAndroid Build Coastguard Worker # Copy static attributes from super class 114*61046927SAndroid Build Coastguard Worker vars().update(vars(states.Inliner)) 115*61046927SAndroid Build Coastguard Worker 116*61046927SAndroid Build Coastguard Worker def quoteInline(self, text): 117*61046927SAndroid Build Coastguard Worker """ 118*61046927SAndroid Build Coastguard Worker `text`: ``str`` 119*61046927SAndroid Build Coastguard Worker Return `text` with inline markup quoted. 120*61046927SAndroid Build Coastguard Worker """ 121*61046927SAndroid Build Coastguard Worker # Method inspired by `states.Inliner.parse` 122*61046927SAndroid Build Coastguard Worker self.document = docutils.utils.new_document("<string>") 123*61046927SAndroid Build Coastguard Worker self.document.settings.trim_footnote_reference_space = False 124*61046927SAndroid Build Coastguard Worker self.document.settings.character_level_inline_markup = False 125*61046927SAndroid Build Coastguard Worker self.document.settings.pep_references = False 126*61046927SAndroid Build Coastguard Worker self.document.settings.rfc_references = False 127*61046927SAndroid Build Coastguard Worker 128*61046927SAndroid Build Coastguard Worker self.init_customizations(self.document.settings) 129*61046927SAndroid Build Coastguard Worker 130*61046927SAndroid Build Coastguard Worker self.reporter = self.document.reporter 131*61046927SAndroid Build Coastguard Worker self.reporter.stream = None 132*61046927SAndroid Build Coastguard Worker self.language = None 133*61046927SAndroid Build Coastguard Worker self.parent = self.document 134*61046927SAndroid Build Coastguard Worker remaining = docutils.utils.escape2null(text) 135*61046927SAndroid Build Coastguard Worker checked = "" 136*61046927SAndroid Build Coastguard Worker processed = [] 137*61046927SAndroid Build Coastguard Worker unprocessed = [] 138*61046927SAndroid Build Coastguard Worker messages = [] 139*61046927SAndroid Build Coastguard Worker while remaining: 140*61046927SAndroid Build Coastguard Worker original = remaining 141*61046927SAndroid Build Coastguard Worker match = self.patterns.initial.search(remaining) 142*61046927SAndroid Build Coastguard Worker if match: 143*61046927SAndroid Build Coastguard Worker groups = match.groupdict() 144*61046927SAndroid Build Coastguard Worker method = self.dispatch[groups['start'] or groups['backquote'] 145*61046927SAndroid Build Coastguard Worker or groups['refend'] or groups['fnend']] 146*61046927SAndroid Build Coastguard Worker before, inlines, remaining, sysmessages = method(self, match, 0) 147*61046927SAndroid Build Coastguard Worker checked += before 148*61046927SAndroid Build Coastguard Worker if inlines: 149*61046927SAndroid Build Coastguard Worker assert len(inlines) == 1, "More than one inline found" 150*61046927SAndroid Build Coastguard Worker inline = original[len(before) 151*61046927SAndroid Build Coastguard Worker :len(original) - len(remaining)] 152*61046927SAndroid Build Coastguard Worker rolePfx = re.search("^:" + self.simplename + ":(?=`)", 153*61046927SAndroid Build Coastguard Worker inline) 154*61046927SAndroid Build Coastguard Worker refSfx = re.search("_+$", inline) 155*61046927SAndroid Build Coastguard Worker if rolePfx: 156*61046927SAndroid Build Coastguard Worker # Prefixed roles need to be quoted in the middle 157*61046927SAndroid Build Coastguard Worker checked += (inline[:rolePfx.end()] + "\\" 158*61046927SAndroid Build Coastguard Worker + inline[rolePfx.end():]) 159*61046927SAndroid Build Coastguard Worker elif refSfx and not re.search("^`", inline): 160*61046927SAndroid Build Coastguard Worker # Pure reference markup needs to be quoted at the end 161*61046927SAndroid Build Coastguard Worker checked += (inline[:refSfx.start()] + "\\" 162*61046927SAndroid Build Coastguard Worker + inline[refSfx.start():]) 163*61046927SAndroid Build Coastguard Worker else: 164*61046927SAndroid Build Coastguard Worker # Quote other inlines by prefixing 165*61046927SAndroid Build Coastguard Worker checked += "\\" + inline 166*61046927SAndroid Build Coastguard Worker else: 167*61046927SAndroid Build Coastguard Worker checked += remaining 168*61046927SAndroid Build Coastguard Worker break 169*61046927SAndroid Build Coastguard Worker # Quote all original backslashes 170*61046927SAndroid Build Coastguard Worker checked = re.sub('\x00', "\\\x00", checked) 171*61046927SAndroid Build Coastguard Worker checked = re.sub('@', '\\@', checked) 172*61046927SAndroid Build Coastguard Worker return docutils.utils.unescape(checked, 1) 173*61046927SAndroid Build Coastguard Worker 174*61046927SAndroid Build Coastguard Workerinliner = Inliner(); 175*61046927SAndroid Build Coastguard Worker 176*61046927SAndroid Build Coastguard Worker 177*61046927SAndroid Build Coastguard Workerasync def gather_commits(version: str) -> str: 178*61046927SAndroid Build Coastguard Worker p = await asyncio.create_subprocess_exec( 179*61046927SAndroid Build Coastguard Worker 'git', 'log', '--oneline', f'mesa-{version}..', '-i', '--grep', r'\(Closes\|Fixes\): \(https\|#\).*', 180*61046927SAndroid Build Coastguard Worker stdout=asyncio.subprocess.PIPE) 181*61046927SAndroid Build Coastguard Worker out, _ = await p.communicate() 182*61046927SAndroid Build Coastguard Worker assert p.returncode == 0, f"git log didn't work: {version}" 183*61046927SAndroid Build Coastguard Worker return out.decode().strip() 184*61046927SAndroid Build Coastguard Worker 185*61046927SAndroid Build Coastguard Worker 186*61046927SAndroid Build Coastguard Workerasync def parse_issues(commits: str) -> typing.List[str]: 187*61046927SAndroid Build Coastguard Worker issues: typing.List[str] = [] 188*61046927SAndroid Build Coastguard Worker for commit in commits.split('\n'): 189*61046927SAndroid Build Coastguard Worker sha, message = commit.split(maxsplit=1) 190*61046927SAndroid Build Coastguard Worker p = await asyncio.create_subprocess_exec( 191*61046927SAndroid Build Coastguard Worker 'git', 'log', '--max-count', '1', r'--format=%b', sha, 192*61046927SAndroid Build Coastguard Worker stdout=asyncio.subprocess.PIPE) 193*61046927SAndroid Build Coastguard Worker _out, _ = await p.communicate() 194*61046927SAndroid Build Coastguard Worker out = _out.decode().split('\n') 195*61046927SAndroid Build Coastguard Worker 196*61046927SAndroid Build Coastguard Worker for line in reversed(out): 197*61046927SAndroid Build Coastguard Worker if not line.lower().startswith(('closes:', 'fixes:')): 198*61046927SAndroid Build Coastguard Worker continue 199*61046927SAndroid Build Coastguard Worker bug = line.split(':', 1)[1].strip() 200*61046927SAndroid Build Coastguard Worker if (bug.startswith('https://gitlab.freedesktop.org/mesa/mesa') 201*61046927SAndroid Build Coastguard Worker # Avoid parsing "merge_requests" URL. Note that a valid issue 202*61046927SAndroid Build Coastguard Worker # URL may or may not contain the "/-/" text, so we check if 203*61046927SAndroid Build Coastguard Worker # the word "issues" is contained in URL. 204*61046927SAndroid Build Coastguard Worker and '/issues' in bug): 205*61046927SAndroid Build Coastguard Worker # This means we have a bug in the form "Closes: https://..." 206*61046927SAndroid Build Coastguard Worker issues.append(os.path.basename(urllib.parse.urlparse(bug).path)) 207*61046927SAndroid Build Coastguard Worker elif ',' in bug: 208*61046927SAndroid Build Coastguard Worker multiple_bugs = [b.strip().lstrip('#') for b in bug.split(',')] 209*61046927SAndroid Build Coastguard Worker if not all(b.isdigit() for b in multiple_bugs): 210*61046927SAndroid Build Coastguard Worker # this is likely a "Fixes" tag that refers to a commit name 211*61046927SAndroid Build Coastguard Worker continue 212*61046927SAndroid Build Coastguard Worker issues.extend(multiple_bugs) 213*61046927SAndroid Build Coastguard Worker elif bug.startswith('#'): 214*61046927SAndroid Build Coastguard Worker issues.append(bug.lstrip('#')) 215*61046927SAndroid Build Coastguard Worker 216*61046927SAndroid Build Coastguard Worker return issues 217*61046927SAndroid Build Coastguard Worker 218*61046927SAndroid Build Coastguard Worker 219*61046927SAndroid Build Coastguard Workerasync def gather_bugs(version: str) -> typing.List[str]: 220*61046927SAndroid Build Coastguard Worker commits = await gather_commits(version) 221*61046927SAndroid Build Coastguard Worker if commits: 222*61046927SAndroid Build Coastguard Worker issues = await parse_issues(commits) 223*61046927SAndroid Build Coastguard Worker else: 224*61046927SAndroid Build Coastguard Worker issues = [] 225*61046927SAndroid Build Coastguard Worker 226*61046927SAndroid Build Coastguard Worker loop = asyncio.get_event_loop() 227*61046927SAndroid Build Coastguard Worker async with aiohttp.ClientSession(loop=loop) as session: 228*61046927SAndroid Build Coastguard Worker results = await asyncio.gather(*[get_bug(session, i) for i in issues]) 229*61046927SAndroid Build Coastguard Worker typing.cast(typing.Tuple[str, ...], results) 230*61046927SAndroid Build Coastguard Worker bugs = list(results) 231*61046927SAndroid Build Coastguard Worker if not bugs: 232*61046927SAndroid Build Coastguard Worker bugs = ['None'] 233*61046927SAndroid Build Coastguard Worker return bugs 234*61046927SAndroid Build Coastguard Worker 235*61046927SAndroid Build Coastguard Worker 236*61046927SAndroid Build Coastguard Workerasync def get_bug(session: aiohttp.ClientSession, bug_id: str) -> str: 237*61046927SAndroid Build Coastguard Worker """Query gitlab to get the name of the issue that was closed.""" 238*61046927SAndroid Build Coastguard Worker # Mesa's gitlab id is 176, 239*61046927SAndroid Build Coastguard Worker url = 'https://gitlab.freedesktop.org/api/v4/projects/176/issues' 240*61046927SAndroid Build Coastguard Worker params = {'iids[]': bug_id} 241*61046927SAndroid Build Coastguard Worker async with session.get(url, params=params) as response: 242*61046927SAndroid Build Coastguard Worker content = await response.json() 243*61046927SAndroid Build Coastguard Worker if not content: 244*61046927SAndroid Build Coastguard Worker # issues marked as "confidential" look like "404" page for 245*61046927SAndroid Build Coastguard Worker # unauthorized users 246*61046927SAndroid Build Coastguard Worker return f'Confidential issue #{bug_id}' 247*61046927SAndroid Build Coastguard Worker else: 248*61046927SAndroid Build Coastguard Worker return content[0]['title'] 249*61046927SAndroid Build Coastguard Worker 250*61046927SAndroid Build Coastguard Worker 251*61046927SAndroid Build Coastguard Workerasync def get_shortlog(version: str) -> str: 252*61046927SAndroid Build Coastguard Worker """Call git shortlog.""" 253*61046927SAndroid Build Coastguard Worker p = await asyncio.create_subprocess_exec('git', 'shortlog', f'mesa-{version}..', 254*61046927SAndroid Build Coastguard Worker stdout=asyncio.subprocess.PIPE) 255*61046927SAndroid Build Coastguard Worker out, _ = await p.communicate() 256*61046927SAndroid Build Coastguard Worker assert p.returncode == 0, 'error getting shortlog' 257*61046927SAndroid Build Coastguard Worker assert out is not None, 'just for mypy' 258*61046927SAndroid Build Coastguard Worker return out.decode() 259*61046927SAndroid Build Coastguard Worker 260*61046927SAndroid Build Coastguard Worker 261*61046927SAndroid Build Coastguard Workerdef walk_shortlog(log: str) -> typing.Generator[typing.Tuple[str, bool], None, None]: 262*61046927SAndroid Build Coastguard Worker for l in log.split('\n'): 263*61046927SAndroid Build Coastguard Worker if l.startswith(' '): # this means we have a patch description 264*61046927SAndroid Build Coastguard Worker yield l.lstrip(), False 265*61046927SAndroid Build Coastguard Worker elif l.strip(): 266*61046927SAndroid Build Coastguard Worker yield l, True 267*61046927SAndroid Build Coastguard Worker 268*61046927SAndroid Build Coastguard Worker 269*61046927SAndroid Build Coastguard Workerdef calculate_next_version(version: str, is_point: bool) -> str: 270*61046927SAndroid Build Coastguard Worker """Calculate the version about to be released.""" 271*61046927SAndroid Build Coastguard Worker if '-' in version: 272*61046927SAndroid Build Coastguard Worker version = version.split('-')[0] 273*61046927SAndroid Build Coastguard Worker if is_point: 274*61046927SAndroid Build Coastguard Worker base = version.split('.') 275*61046927SAndroid Build Coastguard Worker base[2] = str(int(base[2]) + 1) 276*61046927SAndroid Build Coastguard Worker return '.'.join(base) 277*61046927SAndroid Build Coastguard Worker return version 278*61046927SAndroid Build Coastguard Worker 279*61046927SAndroid Build Coastguard Worker 280*61046927SAndroid Build Coastguard Workerdef calculate_previous_version(version: str, is_point: bool) -> str: 281*61046927SAndroid Build Coastguard Worker """Calculate the previous version to compare to. 282*61046927SAndroid Build Coastguard Worker 283*61046927SAndroid Build Coastguard Worker In the case of -rc to final that version is the previous .0 release, 284*61046927SAndroid Build Coastguard Worker (19.3.0 in the case of 20.0.0, for example). for point releases that is 285*61046927SAndroid Build Coastguard Worker the last point release. This value will be the same as the input value 286*61046927SAndroid Build Coastguard Worker for a point release, but different for a major release. 287*61046927SAndroid Build Coastguard Worker """ 288*61046927SAndroid Build Coastguard Worker if '-' in version: 289*61046927SAndroid Build Coastguard Worker version = version.split('-')[0] 290*61046927SAndroid Build Coastguard Worker if is_point: 291*61046927SAndroid Build Coastguard Worker return version 292*61046927SAndroid Build Coastguard Worker base = version.split('.') 293*61046927SAndroid Build Coastguard Worker if base[1] == '0': 294*61046927SAndroid Build Coastguard Worker base[0] = str(int(base[0]) - 1) 295*61046927SAndroid Build Coastguard Worker base[1] = '3' 296*61046927SAndroid Build Coastguard Worker else: 297*61046927SAndroid Build Coastguard Worker base[1] = str(int(base[1]) - 1) 298*61046927SAndroid Build Coastguard Worker return '.'.join(base) 299*61046927SAndroid Build Coastguard Worker 300*61046927SAndroid Build Coastguard Worker 301*61046927SAndroid Build Coastguard Workerdef get_features(is_point_release: bool) -> typing.Generator[str, None, None]: 302*61046927SAndroid Build Coastguard Worker p = pathlib.Path('docs') / 'relnotes' / 'new_features.txt' 303*61046927SAndroid Build Coastguard Worker if p.exists() and p.stat().st_size > 0: 304*61046927SAndroid Build Coastguard Worker if is_point_release: 305*61046927SAndroid Build Coastguard Worker print("WARNING: new features being introduced in a point release", file=sys.stderr) 306*61046927SAndroid Build Coastguard Worker with p.open('rt') as f: 307*61046927SAndroid Build Coastguard Worker for line in f: 308*61046927SAndroid Build Coastguard Worker yield line.rstrip() 309*61046927SAndroid Build Coastguard Worker p.unlink() 310*61046927SAndroid Build Coastguard Worker subprocess.run(['git', 'add', p]) 311*61046927SAndroid Build Coastguard Worker else: 312*61046927SAndroid Build Coastguard Worker yield "None" 313*61046927SAndroid Build Coastguard Worker 314*61046927SAndroid Build Coastguard Worker 315*61046927SAndroid Build Coastguard Workerdef update_release_notes_index(version: str) -> None: 316*61046927SAndroid Build Coastguard Worker relnotes_index_path = pathlib.Path('docs') / 'relnotes.rst' 317*61046927SAndroid Build Coastguard Worker 318*61046927SAndroid Build Coastguard Worker with relnotes_index_path.open('r') as f: 319*61046927SAndroid Build Coastguard Worker relnotes = f.readlines() 320*61046927SAndroid Build Coastguard Worker 321*61046927SAndroid Build Coastguard Worker new_relnotes = [] 322*61046927SAndroid Build Coastguard Worker first_list = True 323*61046927SAndroid Build Coastguard Worker second_list = True 324*61046927SAndroid Build Coastguard Worker for line in relnotes: 325*61046927SAndroid Build Coastguard Worker if first_list and line.startswith('-'): 326*61046927SAndroid Build Coastguard Worker first_list = False 327*61046927SAndroid Build Coastguard Worker new_relnotes.append(f'- :doc:`{version} release notes <relnotes/{version}>`\n') 328*61046927SAndroid Build Coastguard Worker if (not first_list and second_list and 329*61046927SAndroid Build Coastguard Worker re.match(r' \d+.\d+(.\d+)? <relnotes/\d+.\d+(.\d+)?>', line)): 330*61046927SAndroid Build Coastguard Worker second_list = False 331*61046927SAndroid Build Coastguard Worker new_relnotes.append(f' {version} <relnotes/{version}>\n') 332*61046927SAndroid Build Coastguard Worker new_relnotes.append(line) 333*61046927SAndroid Build Coastguard Worker 334*61046927SAndroid Build Coastguard Worker with relnotes_index_path.open('w', encoding='utf-8') as f: 335*61046927SAndroid Build Coastguard Worker for line in new_relnotes: 336*61046927SAndroid Build Coastguard Worker f.write(line) 337*61046927SAndroid Build Coastguard Worker 338*61046927SAndroid Build Coastguard Worker subprocess.run(['git', 'add', relnotes_index_path]) 339*61046927SAndroid Build Coastguard Worker 340*61046927SAndroid Build Coastguard Worker 341*61046927SAndroid Build Coastguard Workerasync def main() -> None: 342*61046927SAndroid Build Coastguard Worker v = pathlib.Path('VERSION') 343*61046927SAndroid Build Coastguard Worker with v.open('rt') as f: 344*61046927SAndroid Build Coastguard Worker raw_version = f.read().strip() 345*61046927SAndroid Build Coastguard Worker is_point_release = '-rc' not in raw_version 346*61046927SAndroid Build Coastguard Worker assert '-devel' not in raw_version, 'Do not run this script on -devel' 347*61046927SAndroid Build Coastguard Worker version = raw_version.split('-')[0] 348*61046927SAndroid Build Coastguard Worker previous_version = calculate_previous_version(version, is_point_release) 349*61046927SAndroid Build Coastguard Worker this_version = calculate_next_version(version, is_point_release) 350*61046927SAndroid Build Coastguard Worker today = datetime.date.today() 351*61046927SAndroid Build Coastguard Worker header = f'Mesa {this_version} Release Notes / {today}' 352*61046927SAndroid Build Coastguard Worker header_underline = '=' * len(header) 353*61046927SAndroid Build Coastguard Worker 354*61046927SAndroid Build Coastguard Worker shortlog, bugs = await asyncio.gather( 355*61046927SAndroid Build Coastguard Worker get_shortlog(previous_version), 356*61046927SAndroid Build Coastguard Worker gather_bugs(previous_version), 357*61046927SAndroid Build Coastguard Worker ) 358*61046927SAndroid Build Coastguard Worker 359*61046927SAndroid Build Coastguard Worker final = pathlib.Path('docs') / 'relnotes' / f'{this_version}.rst' 360*61046927SAndroid Build Coastguard Worker with final.open('wt', encoding='utf-8') as f: 361*61046927SAndroid Build Coastguard Worker try: 362*61046927SAndroid Build Coastguard Worker f.write(TEMPLATE.render( 363*61046927SAndroid Build Coastguard Worker bugfix=is_point_release, 364*61046927SAndroid Build Coastguard Worker bugs=bugs, 365*61046927SAndroid Build Coastguard Worker changes=walk_shortlog(shortlog), 366*61046927SAndroid Build Coastguard Worker features=get_features(is_point_release), 367*61046927SAndroid Build Coastguard Worker gl_version=CURRENT_GL_VERSION, 368*61046927SAndroid Build Coastguard Worker this_version=this_version, 369*61046927SAndroid Build Coastguard Worker header=header, 370*61046927SAndroid Build Coastguard Worker header_underline=header_underline, 371*61046927SAndroid Build Coastguard Worker previous_version=previous_version, 372*61046927SAndroid Build Coastguard Worker vk_version=CURRENT_VK_VERSION, 373*61046927SAndroid Build Coastguard Worker rst_escape=inliner.quoteInline, 374*61046927SAndroid Build Coastguard Worker )) 375*61046927SAndroid Build Coastguard Worker except: 376*61046927SAndroid Build Coastguard Worker print(exceptions.text_error_template().render()) 377*61046927SAndroid Build Coastguard Worker return 378*61046927SAndroid Build Coastguard Worker 379*61046927SAndroid Build Coastguard Worker subprocess.run(['git', 'add', final]) 380*61046927SAndroid Build Coastguard Worker 381*61046927SAndroid Build Coastguard Worker update_release_notes_index(this_version) 382*61046927SAndroid Build Coastguard Worker 383*61046927SAndroid Build Coastguard Worker subprocess.run(['git', 'commit', '-m', 384*61046927SAndroid Build Coastguard Worker f'docs: add release notes for {this_version}']) 385*61046927SAndroid Build Coastguard Worker 386*61046927SAndroid Build Coastguard Worker 387*61046927SAndroid Build Coastguard Workerif __name__ == "__main__": 388*61046927SAndroid Build Coastguard Worker loop = asyncio.get_event_loop() 389*61046927SAndroid Build Coastguard Worker loop.run_until_complete(main()) 390