Skip to content

Commit

Permalink
fix: Authorize fetches to overccome GitHub API rate limit
Browse files Browse the repository at this point in the history
  • Loading branch information
prantlf committed Dec 13, 2023
1 parent 9247551 commit 061abf8
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 10 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,17 @@ Make sure, that you use [Node.js] version 18 or newer.
-n|--name <file-name> archive name without the platform suffix
-p|--platform-suffixes <map> platform name mapping
-a|--arch-suffixes <map> architecture name mapping
-t|--target-dir <dir-name> directory to write the output files to
-e|--unpack-exe unpack the executable and remove the archive
-g|--gh-token <token> GitHub authentication token
-v|--verbose prints extra information on the console
-V|--version print version number and exit
-h|--help print usage instructions and exit

The version specifier is "latest" by default. The file name will be inferred
from the first archive asset found for the current platform, if not specified.
If GitHub token is not specified, variables GITHUB_TOKEN and GH_TOKEN in the
process environment will be checked too.

Examples:
$ grab-github-release -r prantlf/v-jsonlint -p darwin=macos,win32=windows:win64 -u
Expand Down
8 changes: 7 additions & 1 deletion bin/grab-github-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ Options:
-a|--arch-suffixes <map> architecture name mapping
-t|--target-dir <dir-name> directory to write the output files to
-e|--unpack-exe unpack the executable and remove the archive
-g|--gh-token <token> GitHub authentication token
-v|--verbose prints extra information on the console
-V|--version print version number and exit
-h|--help print usage instructions and exit
The version specifier is "latest" by default. The file name will be inferred
from the first archive asset found for the current platform, if not specified.
If GitHub token is not specified, variables GITHUB_TOKEN and GH_TOKEN in the
process environment will be checked too.
Examples:
$ grab-github-release -r prantlf/v-jsonlint -p darwin=macos,win32=windows:win64 -u
Expand All @@ -34,7 +37,7 @@ function fail(message) {

const { argv } = process
let repository, version, name, platformSuffixes, archSuffixes,
targetDirectory, unpackExecutable, verbose
targetDirectory, unpackExecutable, token, verbose

for (let i = 2, l = argv.length; i < l; ++i) {
const arg = argv[i]
Expand Down Expand Up @@ -76,6 +79,9 @@ for (let i = 2, l = argv.length; i < l; ++i) {
case 'e': case 'unpack-exe':
unpackExecutable = flag
return
case 'g': case 'gh-token':
token = match[4] || argv[++i]
return
case 'v': case 'verbose':
verbose = flag
return
Expand Down
25 changes: 16 additions & 9 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,17 @@ async function retry(action) {
}
}

function fetchSafely(url) {
function fetchSafely(url, token) {
return retry(async () => {
log('fetch "%s"', url)
const res = await fetch(url)
/* c8 ignore next 6 */
if (!token) token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN
const options = token ? {
headers: {
Authorization: `Bearer ${token}`
}
} : undefined
const res = await fetch(url, options)
/* c8 ignore next 5 */
if (!res.ok) {
const err = new Error(`GET "${url}" failed: ${res.status} ${res.statusText}`)
Expand Down Expand Up @@ -63,11 +70,11 @@ function getArchiveSuffixes(platformSuffixes, archSuffixes) {
return plats.map(plat => archs.map(arch => `-${plat}-${arch}.zip`)).flat()
}

async function getRelease(name, repo, verspec, platformSuffixes, archSuffixes) {
async function getRelease(name, repo, verspec, platformSuffixes, archSuffixes, token) {
const suffixes = getArchiveSuffixes(platformSuffixes, archSuffixes)
const archives = name && suffixes.map(suffix => `${name}${suffix}`)
const url = `https://api.github.com/repos/${repo}/releases`
const res = await fetchSafely(url)
const res = await fetchSafely(url, token)
const releases = await res.json()
log('%d releases', releases.length)
for (const { tag_name, assets } of releases) {
Expand Down Expand Up @@ -100,9 +107,9 @@ async function getRelease(name, repo, verspec, platformSuffixes, archSuffixes) {
throw new Error(`version matching "${verspec}" not found`)
}

async function download(url, archive) {
async function download(url, archive, token) {
log('download "%s"', url)
const res = await fetchSafely(url)
const res = await fetchSafely(url, token)
await new Promise((resolve, reject) => {
const stream = Readable.fromWeb(res.body)
stream
Expand Down Expand Up @@ -150,14 +157,14 @@ async function makeExecutable(executable) {
}
}

export default async function grab({ name, repository, version, platformSuffixes, archSuffixes, targetDirectory, unpackExecutable, verbose }) {
export default async function grab({ name, repository, version, platformSuffixes, archSuffixes, targetDirectory, unpackExecutable, token, verbose }) {
if (verbose) log = console.log.bind(console)
if (!version) version = 'latest'
const verspec = clean(version) || version
let archive, url;
({ name, version, archive, url } = await getRelease(name, repository, verspec, platformSuffixes, archSuffixes))
({ name, version, archive, url } = await getRelease(name, repository, verspec, platformSuffixes, archSuffixes, token))
if (targetDirectory) archive = join(targetDirectory, archive)
await download(url, archive)
await download(url, archive, token)
if (unpackExecutable) {
const executable = await unpack(archive, targetDirectory)
await makeExecutable(executable)
Expand Down

0 comments on commit 061abf8

Please sign in to comment.