github-api icon indicating copy to clipboard operation
github-api copied to clipboard

Unable to download asset from release in private repository

Open filipjonckers opened this issue 4 years ago • 1 comments

I'm trying to download assets from a private repository - the asset is a jar/zip file which is saved in the latest release. I'm able to connect and see the asset but cannot figure out how to download the asset into a local file using the existing GitHub connection. The response I get when trying to download is: HTTP/1.1 406 Not Acceptable As mentioned in the API documentation, the accept header is set to application/octet-stream I am probably doing something wring in the authentication part...

How should I tackle this?

Source code of a test method:

    private void testGitHubReleaseAssetDownload(final String jwtToken, final String repoFullName) {
        try {
            GitHub githubBuilder = new GitHubBuilder().withJwtToken(jwtToken).build();
            GHAppInstallation appInstallation = githubBuilder.getApp().getInstallationById(GITHUB_APP_INSTALLATION_ID);
            GHAppInstallationToken appInstallationToken = appInstallation.createToken(appInstallation.getPermissions()).create();
            GitHub github = new GitHubBuilder().withAppInstallationToken(appInstallationToken.getToken()).build();
            LOGGER.info("Credentials are: {}", github.isCredentialValid() ? "valid" : "invalid");

            GHRepository repo = github.getRepository(repoFullName);
            GHRelease release = repo.getLatestRelease();
            GHAsset asset = release.listAssets().toList().get(0);

            File file = new File(".", asset.getName());
            String downloadUrl = asset.getBrowserDownloadUrl();
            String githubToken = appInstallationToken.getToken();

            try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
                HttpGet httpGet = new HttpGet(downloadUrl);
                httpGet.addHeader("authorization:", "token " + githubToken);
                httpGet.addHeader("Accept:", "application/octet-stream");
                try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
                    // response: HTTP/1.1 406 Not Acceptable
                    if (httpResponse.getStatusLine().getStatusCode() == 200) {
                        HttpEntity entity = httpResponse.getEntity();
                        if(entity.getContentLength() > 0) {
                            FileUtils.copyInputStreamToFile(entity.getContent(), file);
                        }
                    }
                }
                httpGet.releaseConnection();
            } catch (IOException e) {
                LOGGER.error("unable to download asset: {}", downloadUrl);
            }
        } catch (Exception e) {
            LOGGER.error("ERROR: {}", e.toString());
        }
    }

filipjonckers avatar Jan 12 '21 14:01 filipjonckers

The docs you mentioned are here: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#get-a-release-asset

What To download the asset's binary content, set the "Accept" header of the request to "application/octet-stream" means is that you would do that for the /repos/{owner}/{repo}/releases/assets/{asset_id} URL that currently gets the GHAsset object. For the getBrowserDownloadUrl()` url, I thinking you would not set any Accept header.

For all the work you're doing there, it would be great to add this functionality to the library to replace all the customer httpClient work you're doing.

If you have time, please submit a PR for a new method on GHAsset that takes a StreamConsumer.

bitwiseman avatar Jan 12 '21 20:01 bitwiseman