Mesa (staging/22.0): bin/auto-pick: Add a script that automates applying commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Mar 18 03:11:38 UTC 2022


Module: Mesa
Branch: staging/22.0
Commit: 2bf122cd1ecf0120b96f1ac4e4edd96aaa554364
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=2bf122cd1ecf0120b96f1ac4e4edd96aaa554364

Author: Dylan Baker <dylan.c.baker at intel.com>
Date:   Thu Mar 17 11:00:30 2022 -0700

bin/auto-pick: Add a script that automates applying commits

This attempts to apply each commit, one-by-one, and then pushes it to
gitlab for CI results, then if the CI succeeds it considers the commit a
success, otherwise it reverts it and continues.

---

 bin/auto-pick.py | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 135 insertions(+)

diff --git a/bin/auto-pick.py b/bin/auto-pick.py
new file mode 100755
index 00000000000..1791efd3ba4
--- /dev/null
+++ b/bin/auto-pick.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: MIT
+# Copyright © 2022 Intel Corporation
+
+"""Tool that automatically applies patches and tests them as possible."""
+
+from __future__ import annotations
+import asyncio
+import sys
+import typing
+
+from pick import core
+
+import aiohttp
+
+
+async def revert() -> None:
+    p = await asyncio.create_subprocess_exec(
+        'git', 'reset', '--hard', 'HEAD~',
+        stdout=asyncio.subprocess.DEVNULL,
+        stderr=asyncio.subprocess.DEVNULL,
+    )
+    await p.wait()
+
+
+async def reset() -> None:
+    p = await asyncio.create_subprocess_exec(
+        'git', 'reset', '--hard', 'HEAD',
+        stdout=asyncio.subprocess.DEVNULL,
+        stderr=asyncio.subprocess.DEVNULL,
+    )
+    await p.wait()
+
+
+async def main(loop: asyncio.BaseEventLoop) -> None:
+    commits = await core.update_commits()
+    new_commits = [c for c in commits if
+                   c.nominated and c.resolution is core.Resolution.UNRESOLVED]
+    failed: typing.Set[str] = set()
+
+    with open('VERSION', 'r') as f:
+        version = f.read().split('-')[0].strip()
+    version = '.'.join(version.split('.')[:2])
+    url = 'https://gitlab.freedesktop.org/api/v4/projects/176/pipelines'
+    params = {
+        'ref': f'staging/{version}',
+        'per_page': '1',
+    }
+
+    lock = asyncio.Lock()
+
+    for commit in reversed(new_commits):
+        async with lock:
+            print(f'Commit: {commit.sha}: {commit.description}')
+            if commit.because_sha in failed:
+                # This isn't actually failed, but in a case like:
+                # C requires B, B requires A, A fails to apply
+                # We want C to be excluded as well
+                failed.add(commit.sha)
+                print('  Not applying because the commit it fixes was not applied successfully')
+                continue
+            result, _ = await commit.apply()
+            if not result:
+                failed.add(commit.sha)
+                print(f'  FAILED to apply: {commit.sha}: {commit.description}')
+                await reset()
+                commit.resolution = core.Resolution.MANUAL_RESOLUTION
+                continue
+
+            print('  Compiling project')
+            # TODO: make builddir configureable?
+            p = await asyncio.create_subprocess_exec(
+                'ninja', '-C', 'builddir', 'test',
+                stdout=asyncio.subprocess.DEVNULL,
+                stderr=asyncio.subprocess.DEVNULL,
+            )
+            if await p.wait() != 0:
+                failed.add(commit.sha)
+                print(f'  FAILED to compile: {commit.sha}: {commit.description}, reverting')
+                await revert()
+                commit.resolution = core.Resolution.MANUAL_RESOLUTION
+                continue
+
+            print('  Pushing update to git')
+            p = await asyncio.create_subprocess_exec(
+                'git', 'push', '-f',
+                stdout=asyncio.subprocess.DEVNULL,
+                stderr=asyncio.subprocess.DEVNULL,
+            )
+            if await p.wait() != 0:
+                print('  Critical Error: failed to push to gitlib')
+                await revert()
+                commit.resolution = core.Resolution.MANUAL_RESOLUTION
+                core.save(commits)
+                sys.exit(1)
+
+            print('  Waiting for for CI to finish: ', end='', flush=True)
+            async with aiohttp.ClientSession(loop=loop) as session:
+                async with session.get(url, params=params) as response:
+                    content = await response.json()
+                id_ = content[0]['id']
+                while True:
+                    async with session.get(f'{url}/{id_}') as response:
+                        content = await response.json()
+                    status: str = content['status']
+                    if status in {'created', 'waiting_for_resources', 'preparing', 'pending',
+                                  'running', 'scheduled'}:
+                        print('.', end='', flush=True)
+                        await asyncio.sleep(30)
+                        continue
+                    elif status == 'success':
+                        print(f'\n  Successfully applied: {commit.sha}')
+                        commit.resolution = core.Resolution.MERGED
+                        break
+                    elif status == 'failed':
+                        print(f'\n  CI Failed: {commit.sha}')
+                        failed.add(commit.sha)
+                        await revert()
+                        commit.resolution = core.Resolution.MANUAL_RESOLUTION
+                        break
+                    else:
+                        print(f'\n  Unexpected CI status "{status}": {commit.sha}')
+                        failed.add(commit.sha)
+                        await revert()
+                        commit.resolution = core.Resolution.MANUAL_RESOLUTION
+                        break
+
+    core.save(commits)
+    await core.commit_state()
+    sys.exit(0)
+
+
+if __name__ == "__main__":
+    loop = asyncio.get_event_loop()
+    loop.run_until_complete(main(loop))



More information about the mesa-commit mailing list