|
| 1 | +# a clone of the ruby example https://gist.github.com/valeriomazzeo/5491aee76f758f7352e2e6611ce87ec1 |
| 2 | +import os |
| 3 | +import re |
| 4 | + |
| 5 | +import click |
| 6 | +from github import Github, UnknownObjectException |
| 7 | +# from valid8 import validate not compliant with python 2.7 |
| 8 | + |
| 9 | + |
| 10 | +@click.command() |
| 11 | +@click.option('-u', '--user', help='GitHub username') |
| 12 | +@click.option('-p', '--pwd', help='GitHub password') |
| 13 | +@click.option('-s', '--secret', help='GitHub access token') |
| 14 | +@click.option('-r', '--repo-slug', help='Repo slug. i.e.: apple/swift') |
| 15 | +@click.option('-cf', '--changelog-file', help='Changelog file path') |
| 16 | +@click.option('-d', '--doc-url', help='Documentation url') |
| 17 | +@click.argument('tag') |
| 18 | +def create_or_update_release(user, pwd, secret, repo_slug, changelog_file, doc_url, tag): |
| 19 | + """ |
| 20 | + Creates or updates (TODO) |
| 21 | + a github release corresponding to git tag <TAG>. |
| 22 | + """ |
| 23 | + # 1- AUTHENTICATION |
| 24 | + if user is not None and secret is None: |
| 25 | + # using username and password |
| 26 | + # validate('user', user, instance_of=str) |
| 27 | + assert isinstance(user, str) |
| 28 | + # validate('pwd', pwd, instance_of=str) |
| 29 | + assert isinstance(pwd, str) |
| 30 | + g = Github(user, pwd) |
| 31 | + elif user is None and secret is not None: |
| 32 | + # or using an access token |
| 33 | + # validate('secret', secret, instance_of=str) |
| 34 | + assert isinstance(secret, str) |
| 35 | + g = Github(secret) |
| 36 | + else: |
| 37 | + raise ValueError("You should either provide username/password OR an access token") |
| 38 | + click.echo("Logged in as {user_name}".format(user_name=g.get_user())) |
| 39 | + |
| 40 | + # 2- CHANGELOG VALIDATION |
| 41 | + regex_pattern = "[\s\S]*[\n][#]+[\s]*(?P<title>[\S ]*%s[\S ]*)[\n]+(?P<body>[\s\S]*?)[\n]*(\n#|$)" % re.escape(tag) |
| 42 | + changelog_section = re.compile(regex_pattern) |
| 43 | + if changelog_file is not None: |
| 44 | + # validate('changelog_file', changelog_file, custom=os.path.exists, |
| 45 | + # help_msg="changelog file should be a valid file path") |
| 46 | + assert os.path.exists(changelog_file), "changelog file should be a valid file path" |
| 47 | + with open(changelog_file) as f: |
| 48 | + contents = f.read() |
| 49 | + |
| 50 | + match = changelog_section.match(contents).groupdict() |
| 51 | + if match is None or len(match) != 2: |
| 52 | + raise ValueError("Unable to find changelog section matching regexp pattern in changelog file.") |
| 53 | + else: |
| 54 | + title = match['title'] |
| 55 | + message = match['body'] |
| 56 | + else: |
| 57 | + title = tag |
| 58 | + message = '' |
| 59 | + |
| 60 | + # append footer if doc url is provided |
| 61 | + message += "\n\nSee [documentation page](%s) for details." % doc_url |
| 62 | + |
| 63 | + # 3- REPOSITORY EXPLORATION |
| 64 | + # validate('repo_slug', repo_slug, instance_of=str, min_len=1, help_msg="repo_slug should be a non-empty string") |
| 65 | + assert isinstance(repo_slug, str) and len(repo_slug) > 0, "repo_slug should be a non-empty string" |
| 66 | + repo = g.get_repo(repo_slug) |
| 67 | + |
| 68 | + # -- Is there a tag with that name ? |
| 69 | + try: |
| 70 | + tag_ref = repo.get_git_ref("tags/" + tag) |
| 71 | + except UnknownObjectException: |
| 72 | + raise ValueError("No tag with name %s exists in repository %s" % (tag, repo.name)) |
| 73 | + |
| 74 | + # -- Is there already a release with that tag name ? |
| 75 | + click.echo("Checking if release %s already exists in repository %s" % (tag, repo.name)) |
| 76 | + try: |
| 77 | + release = repo.get_release(tag) |
| 78 | + if release is not None: |
| 79 | + raise ValueError("Release %s already exists in repository %s. Please set overwrite to True if you wish to " |
| 80 | + "update the release (Not yet supported)" % (tag, repo.name)) |
| 81 | + except UnknownObjectException: |
| 82 | + # Release does not exist: we can safely create it. |
| 83 | + click.echo("Creating release %s on repo: %s" % (tag, repo.name)) |
| 84 | + click.echo("Release title: '%s'" % title) |
| 85 | + click.echo("Release message:\n--\n%s\n--\n" % message) |
| 86 | + repo.create_git_release(tag=tag, name=title, |
| 87 | + message=message, |
| 88 | + draft=False, prerelease=False) |
| 89 | + |
| 90 | + # --- Memo --- |
| 91 | + # release.target_commitish # 'master' |
| 92 | + # release.tag_name # '0.5.0' |
| 93 | + # release.title # 'First public release' |
| 94 | + # release.body # markdown body |
| 95 | + # release.draft # False |
| 96 | + # release.prerelease # False |
| 97 | + # # |
| 98 | + # release.author |
| 99 | + # release.created_at # datetime.datetime(2018, 11, 9, 17, 49, 56) |
| 100 | + # release.published_at # datetime.datetime(2018, 11, 9, 20, 11, 10) |
| 101 | + # release.last_modified # None |
| 102 | + # # |
| 103 | + # release.id # 13928525 |
| 104 | + # release.etag # 'W/"dfab7a13086d1b44fe290d5d04125124"' |
| 105 | + # release.url # 'https://api.github.com/repos/smarie/python-pytest-harvest/releases/13928525' |
| 106 | + # release.html_url # 'https://github.com/smarie/python-pytest-harvest/releases/tag/0.5.0' |
| 107 | + # release.tarball_url # 'https://api.github.com/repos/smarie/python-pytest-harvest/tarball/0.5.0' |
| 108 | + # release.zipball_url # 'https://api.github.com/repos/smarie/python-pytest-harvest/zipball/0.5.0' |
| 109 | + # release.upload_url # 'https://uploads.github.com/repos/smarie/python-pytest-harvest/releases/13928525/assets{?name,label}' |
| 110 | + |
| 111 | + |
| 112 | +if __name__ == '__main__': |
| 113 | + create_or_update_release() |
0 commit comments