使用node.js从私有仓库下载zip发行版

4

我正在尝试从私有仓库下载zip发布版,已经尝试了许多解决方案,但是似乎没有一个有效。

以下是我的代码:

function Download(url, path, options) {
updateHeader(options.stageTitles.Downloading)
let received_bytes = 0;
let total_bytes = 0;

// eslint-disable-next-line
console.log('-----------------')
// eslint-disable-next-line
console.log(url, path)
console.log('-----------------')

var req = request(
    {
        method: 'GET',
        uri: url,
        headers: {
            Authorization: `token ${options.gitRepoToken}`,
            'Accept': 'application/octet-stream',
            'User-Agent': 'request module',
        },
        //encoding: null
    }
);

// eslint-disable-next-line
console.log(req)

var out = fs.createWriteStream(path);
req.pipe(out);

req.on('response', data => {
    // eslint-disable-next-line
    console.log(data.headers, data)
    total_bytes = parseInt(data.headers['content-length']);
});

req.on('data', chunk => {
    received_bytes += chunk.length;
    showProgress(received_bytes, total_bytes);
});

req.on('end', () => {
    Install(options)
});}

链接变量等于某个值,例如:https://github.com/SolberLight/PRIVATE_REPO_NAME/releases/download/1.0/MY_ZIP_NAME.zip

看起来我的响应始终是“未找到”的9字节内容大小,因此我猜测我的头信息不正确?

感谢您的帮助!

编辑1: 取得了一些进展,但现在似乎BLOB(二进制大对象)的大小不对。

 (async () => {
    //get latest release
    var response = await axios.get(
        `https://api.github.com/repos/${repoWithOwner}/releases/latest`,
        {
            headers: authHeaders,
        }
    );
    var assets = response.data.assets;
    for (var i = 0; i < assets.length; i++) {
        console.log(assets[i].url);
        response = await axios({
            method: "get",
            url: assets[i].url,
            responseType: "blob",
            headers: {
                //Accept: "application/octet-stream",
                ...authHeaders,
            },
        });
        // eslint-disable-next-line
        console.log(response.data, path)

        let reader = new FileReader()
        reader.onload = function() {
            if (reader.readyState == 2) {
                var buffer = new Buffer(reader.result)
                console.log(`Saving ${JSON.stringify({ fileName: 'myfile.zip', size: response.data.size })}`)
                outputFile(path, buffer, err => {
                    if (err) {
                        // eslint-disable-next-line
                        console.log(err.message)
                    } else {
                        // eslint-disable-next-line
                        console.log(path)
                    }
                })
            }
        }
        reader.readAsArrayBuffer(response.data)
    }
})();
1个回答

5
您可以使用下载存储库归档(zip)端点,文档在此处链接
请考虑以下事项:
  • 您需要执行一个GET请求到/repos/{owner}/{repo}/zipball/{ref}

  • 第一个请求会发送一个重定向(302响应),您需要正确地跟随重定向,在这种情况下,由于您使用的是axios,您需要手动处理。响应将包括一个zipball_url,您将在以下请求中使用它。

  • 由于您正在下载私有仓库发布,因此请考虑这些链接是临时的,并在五分钟后过期。

  • 第一个请求接受用户或安装令牌(如果您作为GitHub应用程序使用API)。了解有关GitHub应用程序和GitHub OAuth应用程序之间差异的更多信息here

  • 如果您正在使用GitHub OAuth应用程序,请确保具有repo范围,对于GitHub应用程序,请确保具有内容权限

请查看以下可行示例:

从GitHub下载zip发布                                                                                 在Fusebit中查看
const owner = 'stack-overflow-demos';

// For the purpose of this example, we have 1 release, so it will be always the first item.
const releases = await installationClient.rest.repos.listReleases({
  owner: 'stack-overflow-demos',
  repo: 'private-demo'
});

// Get release information (e.g zipball URL)
const release = await installationClient.rest.repos.getRelease({
  owner: 'stack-overflow-demos',
  repo: 'private-demo',
  release_id: releases.data[0].id,
});

const { token } = await installationClient.auth();

// According to official GitHub docs https://docs.github.com/en/rest/reference/repos#download-a-repository-archive-zip
// You will get a zipball URL you can use to download the zip file, you need to handle properly the redirects since a second GET
// request is needed, this time with an authenticated URL.
const { zipball_url, tag_name } = release.data;

const response = await getZipFile(zipball_url, token);

// Handle redirects properly if a responseUrl is returned that means you need to perform the redirect,
// you don't need to send the access token to this request, since is a signed URL
// Note: For private repositories, these links are temporary and expire after five minutes.
const {
  request: {
    res: { responseUrl },
  },
} = response;

if (responseUrl) {
  await downloadZipFile(responseUrl, `/tmp/'${tag_name}.zip`);
}

// Get information about the zip file you're about to download
const getZipFile = async (url, token) => {
  return await axios({
    redirect: 'manual',
    method: 'get',
    url,
    headers: {
      Authorization: `token ${token}`,
      Accept: 'application/vnd.github.v3+json',
    },
  });
};

// Download the zip file from the temporary secure URL returned from the first request
const downloadZipFile = async (url, filePath) => {
  const response = await axios({
    method: 'get',
    url,
    responseType: 'stream',
    headers: {
      Accept: 'application/octet-stream',
    },
  });

  return new Promise((resolve, reject) => {
    console.log(`writing to ${filePath}`);
    const dest = fs.createWriteStream(filePath);
    let progress = 0;
    response.data
      .on('end', () => {
        console.log(' Done downloading file.');
        resolve(filePath);
      })
      .on('error', (err) => {
        console.error(' Error downloading file.');
        reject(err);
      })
      .on('data', (d) => {
        progress += d.length;
        console.log(` Downloaded ${progress} bytes`);
      })
      .pipe(dest);
  });
};

这个示例正在使用 Octokit


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接