Example #1
0
def upload_asset(release: GitRelease,
                 path: _PathLike,
                 replace: bool = False,
                 text: bool = False,
                 content: bytes = None) -> None:
    path = Path(path)
    basename = os.path.basename(str(path))
    asset_name = get_gh_asset_name(basename, text)
    asset_label = basename

    for asset in get_release_assets(release, include_incomplete=True):
        if asset_name == asset.name:
            # We want to tread incomplete assets as if they weren't there
            # so replace them always
            if replace or not asset_is_complete(asset):
                asset.delete_asset()
            else:
                print(
                    f"Skipping upload for {asset_name} as {asset_label}, already exists"
                )
                return

    if content is None:
        release.upload_asset(str(path), label=asset_label, name=asset_name)
    else:
        with io.BytesIO(content) as fileobj:
            release.upload_asset_from_memory(  # type: ignore
                fileobj,
                len(content),
                label=asset_label,
                name=asset_name)
    print(f"Uploaded {asset_name} as {asset_label}")
Example #2
0
def erase_old_drafts(repo_full_name):
    gh = get_gh_client()
    ghdb = get_github_db()

    search_for = {
        'url': {
            '$regex': '{}/releases/[0-9]+$'.format(repo_full_name),
        },
        'tag_name': {
            '$regex': '^untagged-',
        },
    }

    for page in get_next_page(ghdb.releases.find(search_for)):
        for raw_release in page:
            document = GitRelease(
                gh._Github__requester,
                {},
                raw_release,
                completed=False,
            )
            doc_id = raw_release['_id']

            try:
                # check if the object still exists
                document.update()
            except UnknownObjectException:
                # if doesn't exist erase from mongo
                ghdb.releases.remove({'_id': doc_id})
            else:
                # if still exist just update
                ghdb.releases.update({'_id': doc_id}, document.raw_data)
Example #3
0
def upload_asset(release: GitRelease,
                 path: _PathLike,
                 replace: bool = False) -> None:
    # type_: msys/mingw/failed
    if not environ.get("CI"):
        print("WARNING: upload skipped, not running in CI")
        return
    path = Path(path)

    basename = os.path.basename(str(path))
    asset_name = get_gh_asset_name(basename)
    asset_label = basename

    for asset in get_release_assets(release, include_incomplete=True):
        if asset_name == asset.name:
            # We want to tread incomplete assets as if they weren't there
            # so replace them always
            if replace or not asset_is_complete(asset):
                asset.delete_asset()
            else:
                print(
                    f"Skipping upload for {asset_name} as {asset_label}, already exists"
                )
                return

    release.upload_asset(str(path), label=asset_label, name=asset_name)
    print(f"Uploaded {asset_name} as {asset_label}")
def publish_release(release: GitRelease) -> None:
    """Publish draft release"""
    print("Publishing new release...")
    release.update_release(
        name=release.title,
        message=release.body,
        draft=False,
    )
Example #5
0
    def _find_source_asset(self, release: GitRelease):
        """Find the right asset."""
        assets = release.get_assets()
        regex = compile(self.config.source_regex)

        candidates = {}

        for asset in assets:
            if regex.fullmatch(asset.name) is not None:
                candidates[asset.name] = asset

        if len(candidates) == 0:
            raise Exception("No valid assets found.")
        elif len(candidates) > 1:
            # Multiple candidates found!

            # Lets check if they are all the same size

            size: Optional[int] = None

            for candidate in candidates.values():
                if size is None:
                    size = candidate.size
                if candidate.size != size:
                    # Multiple distinct assets.
                    assets = sorted(candidates.values(), key=lambda x: x.name)
                    return assets[0]

            # All the same size
        return list(candidates.values())[0]
Example #6
0
    def __get_barrel_asset(self, release: GitRelease) -> GitReleaseAsset:
        # Matching tag download the barrels
        for asset in release.get_assets():
            if self.BARREL_FILE.match(asset.name) is not None:
                return asset

        raise Error(
            "No barrel asset found in release: {rel}".format(rel=release.tag_name)
        )
Example #7
0
def get_assets(release: GitRelease):
    try:
        assets = release.get_assets()
        downloadables = []
        for asset in assets:
            downloadables.append(get_asset(asset))
        return downloadables
    except GithubException as e:
        print("    No assets found")
Example #8
0
def _get_release_by_tag(tag, use_token):
    if use_token:
        token = os.environ.get('GITHUB_TOKEN', False) or open('.token').readline().replace('\n', '')
        g = Github(token)
    else:
        g = Github()
    repo = g.get_user(OWNER).get_repo(REPO)
    headers, data = repo._requester.requestJsonAndCheck(
        "GET",
        repo.url + f'/releases/tags/{tag}'
    )
    return GitRelease(repo._requester, headers, data, completed=True)
Example #9
0
def add_binaries_to_github_release(github_release: GitRelease) -> None:
    """
    Add binaries to a GitHub release.
    """
    # We need to make the artifacts just after creating a tag so that the
    # --version output is exactly the one of the tag.
    # We fetch the latest tags, including the one which was just created.
    for args in (
        ['git', 'fetch', '--tags'],
        ['git', 'merge', 'origin/master'],
        ['git', 'status'],
    ):
        subprocess.run(args=args, check=True)

    linux_artifacts = make_linux_binaries(repo_root=Path('.'))
    for installer_path in linux_artifacts:
        github_release.upload_asset(
            path=str(installer_path),
            label=installer_path.name + '-linux',
        )
        # Remove the installer so that it is not later uploaded by twine.
        installer_path.unlink()
Example #10
0
def get_release_assets(release: GitRelease,
                       include_incomplete=False) -> List[GitReleaseAsset]:
    assets = []
    for asset in release.get_assets():
        # skip in case not fully uploaded yet (or uploading failed)
        if not asset_is_complete(asset) and not include_incomplete:
            continue
        uploader = asset.uploader
        if uploader.type != "Bot" or uploader.login != "github-actions[bot]":
            raise SystemExit(
                f"ERROR: Asset '{get_asset_filename(asset)}' not uploaded "
                f"by GHA but '{uploader.login}'. Aborting.")
        assets.append(asset)
    return assets
Example #11
0
def get_release_assets(release: GitRelease,
                       include_incomplete=False) -> List[GitReleaseAsset]:
    assets = []
    for asset in release.get_assets():
        # skip in case not fully uploaded yet (or uploading failed)
        if not asset_is_complete(asset) and not include_incomplete:
            continue
        uploader = asset.uploader
        uploader_key = (uploader.type, uploader.login)
        # We allow uploads from some users and GHA
        if uploader_key not in ALLOWED_UPLOADERS:
            raise SystemExit(f"ERROR: Asset '{get_asset_filename(asset)}' "
                             f"uploaded by {uploader_key}'. Aborting.")
        assets.append(asset)
    return assets
Example #12
0
def _find_release_asset(release: GitRelease.GitRelease, asset: str) -> str:
    """Return the requested asset's download url from the given release.
    If no specific asset is requested, it will return the first one it comes across.

    :exception ghau.errors.ReleaseAssetError: No asset by given name was found.
    :exception ghau.errors.NoAssetsFoundError: No assets found for given release."""
    al = release.get_assets()
    if al.totalCount == 0:
        raise ge.NoAssetsFoundError(release.tag_name)
    if asset is None:
        return al[0].browser_download_url
    for item in al:
        if item.name == asset:
            log.debug(
                f"Found asset {item.name} with URL: {item.browser_download_url}"
            )
            return item.browser_download_url
        raise ge.ReleaseAssetError(release.tag_name, asset)
Example #13
0
def _find_release_asset(release: GitRelease.GitRelease, asset: str,
                        debug: bool) -> str:  # TODO: detect asset use regex
    """Return the requested asset's download url from the given release.
    If no specific asset is requested, it will return the first one it comes across.

    :exception ghau.errors.ReleaseAssetError: No asset by given name was found.
    :exception ghau.errors.NoAssetsFoundError: No assets found for given release."""
    al = release.get_assets()
    if al.totalCount == 0:  # if there are no assets, abort.
        raise ge.NoAssetsFoundError(release.tag_name)
    if asset is None:  # if no specific asset is requested, download the first it finds.
        return al[0].browser_download_url
    for item in al:  # otherwise, look for the specific asset requested.
        if item.name == asset:
            gf.message(
                "Found asset {} with URL: {}".format(
                    item.name, item.browser_download_url), "debug")
            return item.browser_download_url
        raise ge.ReleaseAssetError(
            release.tag_name,
            asset)  # no asset found by requested name? abort.
Example #14
0
def test_publish_release_final(py_package):
    runner = CliRunner()
    version_spec = "1.5.1rc0"
    changelog = py_package / "CHANGELOG.md"

    # Prep the env
    result = runner.invoke(cli.main,
                           ["prep-env", "--version-spec", version_spec])
    assert result.exit_code == 0, result.output

    # Prep the changelog
    with patch("release_helper.cli.generate_activity_md") as mocked_gen:
        mocked_gen.return_value = CHANGELOG_ENTRY
        result = runner.invoke(
            cli.main, ["prep-changelog", "--changelog-path", changelog])
    assert result.exit_code == 0, result.output

    # Create the dist files
    run("python -m build .")

    # Finalize the release
    result = runner.invoke(cli.main, ["prep-release"])

    # Publish the release
    repo = Repository(None, dict(), dict(), True)
    release = GitRelease(None, dict(), dict(), True)

    repo.create_git_release = release_mock = MagicMock(return_value=release)
    release.delete_release = delete_mock = MagicMock()

    with patch.object(cli.Github, "get_repo",
                      return_value=repo) as mock_method:
        result = runner.invoke(
            cli.main, ["publish-release", "--post-version-spec", "1.5.2.dev0"])
    assert result.exit_code == 0, result.output
    release_mock.assert_called_once()
    delete_mock.assert_not_called()
Example #15
0
 def get_assets(self, rel: GitRelease) -> List[GitReleaseAsset]:
     return list(rel.get_assets())