Created Keep Running (kr) command
This commit is contained in:
commit
510d299276
|
@ -0,0 +1,18 @@
|
||||||
|
name: Bonsai CI
|
||||||
|
run-name: ${{ gitea.actor }} is running spotify.local CI pipeline 🚀
|
||||||
|
on: [release]
|
||||||
|
concurrency: 'true'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Download dependencies
|
||||||
|
run: npm ci
|
||||||
|
- name: Build binairy files
|
||||||
|
run: npm run build
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
path: bin
|
|
@ -0,0 +1,3 @@
|
||||||
|
.idea/
|
||||||
|
node_modules/
|
||||||
|
out/
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SLEEP=${1:-'10'}
|
||||||
|
|
||||||
|
echo "Sleeping for $SLEEP seconds...";
|
||||||
|
|
||||||
|
sleep $SLEEP;
|
||||||
|
|
||||||
|
echo "Waking up!";
|
||||||
|
|
||||||
|
exit 1;
|
|
@ -0,0 +1,213 @@
|
||||||
|
{
|
||||||
|
"name": "kr",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "kr",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"yargs": "^17.7.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"kr": "src/index.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.8.10",
|
||||||
|
"@types/yargs": "^17.0.29"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "20.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.2.tgz",
|
||||||
|
"integrity": "sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/yargs": {
|
||||||
|
"version": "17.0.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz",
|
||||||
|
"integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/yargs-parser": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/yargs-parser": {
|
||||||
|
"version": "21.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
|
||||||
|
"integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/ansi-regex": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cliui": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"strip-ansi": "^6.0.1",
|
||||||
|
"wrap-ansi": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
|
},
|
||||||
|
"node_modules/emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||||
|
},
|
||||||
|
"node_modules/escalade": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-caller-file": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||||
|
"engines": {
|
||||||
|
"node": "6.* || 8.* || >= 10.*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/require-directory": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/string-width": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strip-ansi": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/y18n": {
|
||||||
|
"version": "5.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs": {
|
||||||
|
"version": "17.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||||
|
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"cliui": "^8.0.1",
|
||||||
|
"escalade": "^3.1.1",
|
||||||
|
"get-caller-file": "^2.0.5",
|
||||||
|
"require-directory": "^2.1.1",
|
||||||
|
"string-width": "^4.2.3",
|
||||||
|
"y18n": "^5.0.5",
|
||||||
|
"yargs-parser": "^21.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs-parser": {
|
||||||
|
"version": "21.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||||
|
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "kr",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"bin": "src/index.js",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "pkg package.json"
|
||||||
|
},
|
||||||
|
"pkg": {
|
||||||
|
"scripts": "src/**/*.js",
|
||||||
|
"targets": [
|
||||||
|
"node18-linux-x64",
|
||||||
|
"node18-macos-x64",
|
||||||
|
"node18-win-x64"
|
||||||
|
],
|
||||||
|
"outputPath": "out"
|
||||||
|
},
|
||||||
|
"author": "Ian Wijma",
|
||||||
|
"dependencies": {
|
||||||
|
"yargs": "^17.7.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.8.10",
|
||||||
|
"@types/yargs": "^17.0.29"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
const Yargs = require('yargs');
|
||||||
|
const {spawn} = require("child_process");
|
||||||
|
|
||||||
|
const SECONDS_IN_A_MINUTE = 60;
|
||||||
|
const SECONDS_IN_A_HOUR = 60 * 60;
|
||||||
|
|
||||||
|
const yargs = Yargs(process.argv.splice(2))
|
||||||
|
.scriptName('kr')
|
||||||
|
.usage('kr [args] <thing-to-run>')
|
||||||
|
.option('rpm', {
|
||||||
|
default: 0,
|
||||||
|
description: 'The amount of Retries Per Minute, before we stop retrying',
|
||||||
|
type: 'number'
|
||||||
|
})
|
||||||
|
.option('rph', {
|
||||||
|
default: 0,
|
||||||
|
description: 'The amount of Retries Per Hour, before we stop retrying',
|
||||||
|
type: 'number'
|
||||||
|
})
|
||||||
|
.help();
|
||||||
|
|
||||||
|
const { _ = [], rpm, rph } = yargs.argv;
|
||||||
|
const [command, ...args ] = _;
|
||||||
|
|
||||||
|
if (!command) {
|
||||||
|
return yargs.showHelp();
|
||||||
|
}
|
||||||
|
|
||||||
|
let historyMax = 4;
|
||||||
|
let seconds = SECONDS_IN_A_MINUTE;
|
||||||
|
let restartName = 'minute';
|
||||||
|
|
||||||
|
if (rpm && rph) {
|
||||||
|
return console.error('Currently, can not define both --rpm and --rph, please choose only one.');
|
||||||
|
} else if (rpm) {
|
||||||
|
historyMax = rpm
|
||||||
|
} else if (rph) {
|
||||||
|
historyMax = rph
|
||||||
|
seconds = SECONDS_IN_A_HOUR
|
||||||
|
restartName = 'hour'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object<number, string>}
|
||||||
|
*/
|
||||||
|
const history = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} logs
|
||||||
|
*/
|
||||||
|
const pushHistory = (logs) => history[(new Date).getTime()] = logs;
|
||||||
|
|
||||||
|
const updateHistory = () => {
|
||||||
|
const clearKeys = [];
|
||||||
|
|
||||||
|
const maxAge = (new Date).getTime() + seconds;
|
||||||
|
for (const historyTime in history) {
|
||||||
|
if (historyTime > maxAge) {
|
||||||
|
clearKeys.push(historyTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearKeys.forEach((key) => delete history[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkHistory = () => Object.keys(history).length <= historyMax;
|
||||||
|
|
||||||
|
const runCommand = () => {
|
||||||
|
console.log(`Running ${command} ${args.join(' ')}`);
|
||||||
|
const runner = spawn(command, args);
|
||||||
|
|
||||||
|
const commandLogs = [];
|
||||||
|
|
||||||
|
const pushLog = (logEntry) => commandLogs.push(logEntry);
|
||||||
|
|
||||||
|
const trimLog = () => {
|
||||||
|
if(commandLogs.length > 5000) commandLogs.shift()
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearLogs = () => commandLogs.length = 0;
|
||||||
|
|
||||||
|
const getLogs = () => commandLogs.join('\n');
|
||||||
|
|
||||||
|
const handleOut = (type, message) => {
|
||||||
|
pushLog(`[${type}]\t${message}`);
|
||||||
|
trimLog();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleExit = (exitCode) => {
|
||||||
|
console.log(`[CRASH] exit code: ${exitCode}`)
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
pushHistory(getLogs());
|
||||||
|
clearLogs();
|
||||||
|
updateHistory();
|
||||||
|
if (checkHistory()) {
|
||||||
|
console.log('Restarting...');
|
||||||
|
runCommand();
|
||||||
|
} else {
|
||||||
|
console.error(`The process crashed more then ${historyMax} times in the past ${restartName}, stop retrying.`);
|
||||||
|
console.error(`See below the past ${historyMax} crashes:`);
|
||||||
|
for (const time in history) {
|
||||||
|
console.error(`Crash @ ${time}:\n${history[time]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runner.on('close', (exitCode) => handleExit(exitCode))
|
||||||
|
runner.stdout.on('data', (data) => console.log(data.toString().trim()))
|
||||||
|
runner.stdout.on('data', (data) => handleOut('stdout', data.toString().trim()))
|
||||||
|
runner.stderr.on('data', (data) => handleOut('stderr', data.toString().trim()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command goes BRRRR
|
||||||
|
runCommand();
|
Loading…
Reference in New Issue