From 22aa8ba596a4fa92eee8552cf2815c54e9932331 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Sun, 15 Jan 2023 02:00:52 +0000 Subject: [PATCH] feat(releases): add github source releases (no assets) --- _common/github-source.js | 133 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 _common/github-source.js diff --git a/_common/github-source.js b/_common/github-source.js new file mode 100644 index 0000000..93382d1 --- /dev/null +++ b/_common/github-source.js @@ -0,0 +1,133 @@ +'use strict'; + +require('dotenv').config(); + +/** + * Gets the releases for 'ripgrep'. This function could be trimmed down and made + * for use with any github release. + * + * @param request + * @param {string} owner + * @param {string} repo + * @returns {PromiseLike | Promise} + */ +async function getAllReleases( + request, + owner, + repo, + oses, + arches, + baseurl = 'https://api.github.com' +) { + if (!owner) { + return Promise.reject('missing owner for repo'); + } + if (!repo) { + return Promise.reject('missing repo name'); + } + + let req = { + url: `${baseurl}/repos/${owner}/${repo}/releases`, + json: true + }; + + // TODO I really don't like global config, find a way to do better + if (process.env.GITHUB_USERNAME) { + req.auth = { + user: process.env.GITHUB_USERNAME, + pass: process.env.GITHUB_TOKEN + }; + } + + let resp = await request(req); + let gHubResp = resp.body; + let all = { + releases: [], + // TODO make this ':baseurl' + ':releasename' + download: '' + }; + + for (let release of gHubResp) { + // TODO tags aren't always semver / sensical + let tag = release['tag_name']; + let lts = /(\b|_)(lts)(\b|_)/.test(release['tag_name']); + let channel = 'stable'; + if (release['prerelease']) { + channel = 'beta'; + } + let date = release['published_at'] || ''; + date = date.replace(/T.*/, ''); + + let urls = [release.tarball_url, release.zipball_url]; + for (let url of urls) { + let resp = await request({ + method: 'HEAD', + followRedirect: true, + followAllRedirects: true, + followOriginalHttpMethod: true, + url: url, + stream: true + }); + // Workaround for bug where method changes to GET + resp.destroy(); + + // content-disposition: attachment; filename=BeyondCodeBootcamp-DuckDNS.sh-v1.0.1-0-ga2f4bde.zip + let name = resp.headers['content-disposition'].replace( + /.*filename=([^;]+)(;|$)/, + '$1' + ); + all.releases.push({ + name: name, + version: tag, + lts: lts, + channel: channel, + date: date, + os: '', // will be guessed by download filename + arch: '', // will be guessed by download filename + ext: '', // will be normalized + download: resp.request.uri.href + }); + } + } + + if (oses) { + return combinate(all, oses, arches); + } + + return all; +} + +function combinate(all, oses, arches) { + let releases = all.releases; + // ex: arches = ['amd64', 'arm64', 'armv7l', 'armv6l', 'x86']; + // ex: oses = ['macos', 'linux', 'bsd', 'posix']; + + let combos = []; + for (let release of releases) { + for (let arch of arches) { + for (let os of oses) { + let combo = { + arch: arch, + os: os + }; + let rel = Object.assign({}, release, combo); + combos.push(rel); + } + } + } + all.releases = combos; + + return all; +} + +module.exports = getAllReleases; + +if (module === require.main) { + getAllReleases( + require('@root/request'), + 'BeyondCodeBootcamp', + 'DuckDNS.sh' + ).then(function (all) { + console.info(JSON.stringify(all, null, 2)); + }); +}