| 1 | # pip install click gitpython |
| 2 | |
| 3 | # Usage: |
| 4 | |
| 5 | # python tools\devops\find-release.py src/windows/wsl/main.cpp 10 |
| 6 | # python tools\devops\find-release.py --commit 4ec2def9f3f588c06308cb31cb758e5369761aa5 |
| 7 | |
| 8 | import click |
| 9 | import re |
| 10 | |
| 11 | from git import Repo, Commit, Tag |
| 12 | |
| 13 | @click.command() |
| 14 | @click.argument('ref', required=True, type=str) |
| 15 | @click.argument('line', default=None, required=False, type=int) |
| 16 | @click.option('--commit', is_flag=True) |
| 17 | def main(ref: str, line: int, commit: bool): |
| 18 | repo = Repo('.') |
| 19 | |
| 20 | repo.remote('origin').fetch() |
| 21 | tags = list_tags(repo) |
| 22 | |
| 23 | if commit: |
| 24 | change = repo.commit(ref) |
| 25 | click.secho(f'{ref}: {find_tag_for_commit(repo, tags, change)}', fg='green', bold=True) |
| 26 | else: |
| 27 | |
| 28 | for entry in repo.blame_incremental('HEAD', ref): |
| 29 | if line >= entry.linenos.start and line <= entry.linenos.stop: |
| 30 | click.secho(f'Changed in {find_tag_for_commit(repo, tags, entry.commit)} by {entry.commit.hexsha}', fg='green', bold=True) |
| 31 | |
| 32 | print(repo.git.diff(entry.commit, entry.commit.parents[0], ref) + '\n') |
| 33 | |
| 34 | |
| 35 | def list_tags(repo: Repo) -> list: |
| 36 | return [e for e in sorted(repo.tags, key=lambda e: e.path) if re.match('refs/tags/[0-9]+\\.[0-9]+\\.[0-9]+', e.path)] |
| 37 | |
| 38 | def find_tag_for_commit(repo: Repo, tags: list, commit: Commit) -> str: |
| 39 | for e in tags: |
| 40 | merge_bases = repo.merge_base(e, commit) |
| 41 | |
| 42 | if any(e == commit for e in merge_bases): |
| 43 | return e.path.replace('refs/tags/', '') |
| 44 | |
| 45 | return "[No tag found]" |
| 46 | |
| 47 | if __name__ == '__main__': |
| 48 | main() |