ref!: release info from git tags

This commit is contained in:
AJ ONeal
2023-10-31 15:09:48 -06:00
parent 8926e27d41
commit 5dd3a79faa
7 changed files with 233 additions and 129 deletions
+145
View File
@@ -0,0 +1,145 @@
'use strict';
require('dotenv').config({ path: '.env' });
if (!process.env.REPO_BASE_DIR) {
// for stderr
console.error('[Warn] REPO_BASE_DIR= not set, using ./repos/');
}
// ../ because this script is one directory deep
let repoBaseDir = process.env.REPO_BASE_DIR || '../repos';
var Crypto = require('crypto');
var util = require('util');
var exec = util.promisify(require('child_process').exec);
var Fs = require('node:fs/promises');
var Repos = {};
Repos.clone = async function (gitUrl, repoPath) {
let uuid = Crypto.randomUUID();
let tmpPath = `${repoPath}.${uuid}.tmp`;
await exec(`git clone --bare --filter=tree:0 ${gitUrl} ${tmpPath}`);
await Fs.rename(tmpPath, repoPath);
};
Repos.checkExists = async function (repoPath) {
let err = await Fs.access(repoPath).catch(Object);
if (!err) {
return true;
}
if (err.code !== 'ENOENT') {
throw err;
}
return false;
};
Repos.getTags = async function (repoPath) {
var { stdout } = await exec(`git --git-dir=${repoPath} tag`);
var rawTags = stdout.trim().split('\n');
let tags = [];
for (let tag of rawTags) {
// ex: v1, v2, v1.1, 1.1.0-rc
let maybeVersionRe = /^(v\d+|v?\d+\.\d+)/;
let maybeVersion = maybeVersionRe.test(tag);
if (maybeVersion) {
tags.push(tag);
}
// TODO date versions
// let maybeVersionDate = /^v?\d{4}[._-]\d{2}[._-]\d{2}[._-]\D/.test(tag);
}
tags = tags.reverse();
return tags;
};
Repos.getCommitInfo = async function (repoPath, commitish) {
var { stdout } = await exec(
`git --git-dir=${repoPath} log -1 --format="%h %H %ad %cd" --date=iso-strict ${commitish}`,
);
stdout = stdout.trim();
var commitParts = stdout.split(/\s+/g);
return {
commit_id: `${commitParts[0]}`,
commit: `${commitParts[1]}`,
date: commitParts[2],
date_authored: commitParts[3],
};
};
/**
* Lists GitHub Releases (w/ uploaded assets)
*
* @param request
* @param {string} owner
* @param {string} gitUrl
* @returns {PromiseLike<any> | Promise<any>}
*/
async function getAllReleases(gitUrl) {
let all = {
releases: [],
download: '',
};
let repoName = gitUrl.split('/').pop();
repoName = repoName.replace(/\.git$/, '');
let repoPath = `${repoBaseDir}/${repoName}.git`;
let isCloned = await Repos.checkExists(repoPath);
if (!isCloned) {
await Repos.clone(gitUrl, repoPath);
}
let releases = [];
let tags = await Repos.getTags(repoPath);
for (let tag of tags) {
let commitInfo = await Repos.getCommitInfo(repoPath, tag);
let date = new Date(commitInfo.date);
let version = tag.replace(/^v/, '');
let rel = {
name: `${repoName}-v${version}`,
version: tag,
git_tag: tag,
git_commit_hash: commitInfo.commit_id,
//git_long_commit_hash: commitInfo.commit,
lts: false,
channel: '',
date: date.toISOString(),
os: '*',
arch: '*',
ext: 'git',
//command: `git clone --depth=1 --single-branch --branch ${tag} ${gitUrl}`,
download: gitUrl,
};
releases.push(rel);
}
all.releases = releases;
return all;
}
module.exports = getAllReleases;
if (module === require.main) {
(async function main() {
let all = await getAllReleases('https://github.com/dense-analysis/ale.git');
// for stderr
let sample = JSON.stringify(all.releases[0], null, 2);
console.error('Sample:');
console.error(sample);
all = require('../_webi/normalize.js')(all);
console.info(JSON.stringify(all, null, 2));
})()
.then(function () {
process.exit(0);
})
.catch(function (err) {
console.error(err);
});
}
-97
View File
@@ -1,97 +0,0 @@
'use strict';
require('dotenv').config({ path: '.env' });
if (!process.env.REPO_BASE_DIR) {
console.warn('[Warn] REPO_BASE_DIR= not set, using ./repos/');
}
// ../ because this script is one directory deep
let repoBaseDir = process.env.REPO_BASE_DIR || '../repos';
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const fs = require('fs').promises;
/**
* Lists GitHub Releases (w/ uploaded assets)
*
* @param request
* @param {string} owner
* @param {string} gitUrl
* @returns {PromiseLike<any> | Promise<any>}
*/
async function getAllReleases(gitUrl) {
const all = {
releases: [],
download: ''
};
const repoName = gitUrl.split('/').pop();
const repoPath = `${repoBaseDir}/${repoName}`;
// Function to clone the repository if it doesn't exist
async function cloneRepository() {
if (!(await repoExists())) {
await exec(`git clone --bare ${gitUrl} ${repoPath}`);
}
}
// Function to check if the repository already exists
async function repoExists() {
try {
await fs.access(repoPath);
return true;
} catch (error) {
return false;
}
}
// Function to list all version tags
async function listVersionTags() {
await cloneRepository();
const { stdout } = await exec(`git --git-dir=${repoPath} tag`);
const tags = stdout.trim().split('\n');
return tags;
}
// Function to create an array of release info objects
async function createReleaseInfo() {
const tags = await listVersionTags();
const releaseInfo = [];
for (const tag of tags) {
const { stdout: tagDate } = await exec(
`git --git-dir=${repoPath} log -1 --format=%ad --date=iso ${tag}`
);
const tagObject = {
name: `${repoName}-v${tag}`,
version: tag,
date: tagDate.trim(),
ext: 'git',
command: `git clone --depth=1 --single-branch --branch ${tag} ${gitUrl}`
};
releaseInfo.push(tagObject);
}
return releaseInfo;
}
all.releases = await createReleaseInfo();
return all;
}
module.exports = getAllReleases;
if (module === require.main) {
(async function main() {
let all = await getAllReleases('https://github.com/jshint/jshint');
console.log(all.releases[0]);
all = require('../_webi/normalize.js')(all);
console.info(JSON.stringify(all, null, 2));
})()
.then(function () {
process.exit(0);
})
.catch(function (err) {
console.error(err);
});
}
+1 -1
View File
@@ -20,7 +20,7 @@ Object.keys(osMap).forEach(function (name) {
maps.oses[name] = true;
});
var formats = ['zip', 'xz', 'tar', 'pkg', 'msi', 'git', 'exe', 'dmg'];
var formats = ['zip', 'xz', 'tar', 'pkg', 'msi', 'git', 'exe', 'dmg', 'git'];
formats.forEach(function (name) {
maps.formats[name] = true;
});
+42 -26
View File
@@ -114,6 +114,10 @@ Releases.renderBash = async function (
.replace(/^\s*#?WEBI_MINOR=.*/m, 'WEBI_MINOR=' + v.minor)
.replace(/^\s*#?WEBI_PATCH=.*/m, 'WEBI_PATCH=' + v.patch)
.replace(/^\s*#?WEBI_BUILD=.*/m, 'WEBI_BUILD=' + v.build)
.replace(
/^\s*#?WEBI_GIT_TAG=.*/m,
"WEBI_GIT_TAG='" + rel.git_tag + "'",
)
.replace(/^\s*#?WEBI_LTS=.*/m, 'WEBI_LTS=' + rel.lts)
.replace(/^\s*#?WEBI_CHANNEL=.*/m, 'WEBI_CHANNEL=' + rel.channel)
.replace(
@@ -187,32 +191,44 @@ Releases.renderPowerShell = async function (
.readFile(path.join(__dirname, 'template.ps1'), 'utf8')
.then(function (tplTxt) {
var pkgver = pkg + '@' + ver;
return tplTxt
.replace(
/^(#)?\$Env:WEBI_HOST\s*=.*/im,
"$Env:WEBI_HOST = '" + baseurl + "'",
)
.replace(
/^(#)?\$Env:WEBI_PKG\s*=.*/im,
"$Env:WEBI_PKG = '" + pkgver + "'",
)
.replace(
/^(#)?\$Env:PKG_NAME\s*=.*/im,
"$Env:PKG_NAME = '" + pkg + "'",
)
.replace(
/^(#)?\$Env:WEBI_VERSION\s*=.*/im,
"$Env:WEBI_VERSION = '" + rel.version + "'",
)
.replace(
/^(#)?\$Env:WEBI_PKG_URL\s*=.*/im,
"$Env:WEBI_PKG_URL = '" + rel.download + "'",
)
.replace(
/^(#)?\$Env:WEBI_PKG_FILE\s*=.*/im,
"$Env:WEBI_PKG_FILE = '" + rel.name + "'",
)
.replace(reInstallTpl, '\n' + installTxt);
return (
tplTxt
.replace(
/^(#)?\$Env:WEBI_HOST\s*=.*/im,
"$Env:WEBI_HOST = '" + baseurl + "'",
)
.replace(
/^(#)?\$Env:WEBI_PKG\s*=.*/im,
"$Env:WEBI_PKG = '" + pkgver + "'",
)
.replace(
/^(#)?\$Env:PKG_NAME\s*=.*/im,
"$Env:PKG_NAME = '" + pkg + "'",
)
.replace(
/^(#)?\$Env:WEBI_VERSION\s*=.*/im,
"$Env:WEBI_VERSION = '" + rel.version + "'",
)
.replace(
/^(#)?\$Env:WEBI_GIT_TAG\s*=.*/im,
"$Env:WEBI_GIT_TAG = '" + rel.git_tag + "'",
)
.replace(
/^(#)?\$Env:WEBI_PKG_URL\s*=.*/im,
"$Env:WEBI_PKG_URL = '" + rel.download + "'",
)
// TODO replace WEBI_PKG_FILE (which is sometimes a dir)
.replace(
/^(#)?\$Env:WEBI_PKG_PATHNAME\s*=.*/im,
"$Env:WEBI_PKG_PATHNAME = '" + rel.name + "'",
)
// TODO deprecate
.replace(
/^(#)?\$Env:WEBI_PKG_FILE\s*=.*/im,
"$Env:WEBI_PKG_FILE = '" + rel.name + "'",
)
.replace(reInstallTpl, '\n' + installTxt)
);
});
});
};
+36
View File
@@ -25,6 +25,7 @@ __bootstrap_webi() {
#WEBI_PATCH=
# TODO not sure if BUILD is the best name for this
#WEBI_BUILD=
#WEBI_GIT_TAG=
#WEBI_LTS=
#WEBI_CHANNEL=
#WEBI_EXT=
@@ -248,6 +249,32 @@ __bootstrap_webi() {
echo "Saved as ${my_dl_rel}"
}
webi_git_clone() { (
my_url="${1}"
my_dl="${2}"
my_dl_rel="$(
webi_sub_home "${my_dl}"
)"
if [ -e "${my_dl}" ]; then
echo "Found ${my_dl_rel}"
cp -RPp "${my_dl}" "${WEBI_TMP}/${WEBI_PKG_FILE}/"
return 0
fi
echo "Cloning ${my_url}"
cmd_git="git clone --config advice.detachedHead=false --quiet --depth=1 --single-branch"
rm -rf "${my_dl}.part"
if ! $cmd_git "${my_url}" --branch "${WEBI_GIT_TAG}" "${my_dl}.part"; then
echo >&2 "failed to git clone ${WEBI_PKG_URL}"
exit 1
fi
mv "${my_dl}.part" "${my_dl}"
cp -RPp "${my_dl}" "${WEBI_TMP}/${WEBI_PKG_FILE}/"
); }
# detect which archives can be used
webi_extract() {
(
@@ -265,6 +292,9 @@ __bootstrap_webi() {
elif [ "exe" = "$WEBI_EXT" ]; then
echo "Moving ${my_dl_rel}"
mv "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" .
elif [ "git" = "$WEBI_EXT" ]; then
echo "Moving ${my_dl_rel}"
mv "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" .
elif [ "xz" = "$WEBI_EXT" ]; then
echo "Inflating ${my_dl_rel}"
unxz -c "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > "$(basename "$WEBI_PKG_FILE")"
@@ -456,6 +486,12 @@ __bootstrap_webi() {
webi_pre_install() {
webi_check_installed
webi_check_available
if test "git" = "${WEBI_EXT}"; then
webi_git_clone \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
return 0
fi
webi_download \
"${WEBI_PKG_URL}" \
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
+8 -4
View File
@@ -182,14 +182,18 @@ async function filterReleases(
function selectMatches(rel) {
if (os) {
if (rel.os !== os) {
return false;
if (rel.os !== '*') {
if (rel.os !== os) {
return false;
}
}
}
if (arch) {
if (rel.arch !== arch) {
return false;
if (rel.arch !== '*') {
if (rel.arch !== arch) {
return false;
}
}
}
+1 -1
View File
@@ -100,7 +100,7 @@ if ($exename -eq "-V" -or $exename -eq "--version" -or $exename -eq "version" -o
# Fetch <whatever>.ps1
# TODO detect formats
$PKG_URL = "$Env:WEBI_HOST/api/installers/$exename.ps1?formats=zip,exe,tar"
$PKG_URL = "$Env:WEBI_HOST/api/installers/$exename.ps1?formats=zip,exe,tar,git"
Write-Output "Downloading $PKG_URL"
# Invoke-WebRequest -UserAgent "Windows amd64" "$PKG_URL" -OutFile ".\.local\tmp\$exename.install.ps1"
& curl.exe -fsSL -A "$Env:WEBI_UA" "$PKG_URL" -o .\.local\tmp\$exename.install.ps1