Convert everything over to TypeScript
This was mostly minor minor tweaking of imports and fiddling with a few types
This commit is contained in:
parent
7b539d05c2
commit
044ba25859
|
@ -8,6 +8,8 @@ lint:: compile
|
|||
|
||||
check:: compile
|
||||
|
||||
unit:: compile
|
||||
|
||||
compile:
|
||||
tsc
|
||||
|
||||
|
@ -27,6 +29,6 @@ run: depends build
|
|||
EVERGREEN_DISABLE_SNAPSHOT=true \
|
||||
EVERGREEN_ENDPOINT=http://127.0.0.1:3030 \
|
||||
FLAVOR=docker-cloud \
|
||||
npm run client
|
||||
npm run start
|
||||
|
||||
.PHONY: run build docs compile
|
||||
|
|
|
@ -173,6 +173,12 @@
|
|||
"integrity": "sha512-ojnbBiKkZFYRfQpmtnnWTMw+rzGp/JiystjluW9jgN3VzRwilXddJ6aGQ9V/7iuDG06SBgn7ozW9k3zcAnYjYQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.33.tgz",
|
||||
"integrity": "sha1-EHPEvIJHVK49EM+riKsCN7qWTk0=",
|
||||
"dev": true
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.5.13",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.5.13.tgz",
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
"description": "",
|
||||
"main": "src/client.js",
|
||||
"scripts": {
|
||||
"client": "node src/client.js",
|
||||
"test": "npm run eslint && npm run jest",
|
||||
"eslint": "eslint src/. test/. --config .eslintrc.json",
|
||||
"jest": "jest",
|
||||
"prestart": "tsc",
|
||||
"start": "node build/client.js",
|
||||
"pretest": "eslint src/. test/. --config .eslintrc.json",
|
||||
"eslint": "npm run pretest",
|
||||
"test": "jest",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"author": "R Tyler Croy",
|
||||
|
@ -15,6 +16,8 @@
|
|||
"devDependencies": {
|
||||
"@types/feathersjs__feathers": "^3.0.5",
|
||||
"@types/jest": "^23.3.3",
|
||||
"@types/node": "^10.11.4",
|
||||
"@types/tmp": "0.0.33",
|
||||
"asciidoctor.js": "^1.5.7-rc.1",
|
||||
"css-loader": "^1.0.0",
|
||||
"eslint": "^4.19.1",
|
||||
|
@ -60,11 +63,23 @@
|
|||
"<rootDir>/ui/index.js",
|
||||
"<rootDir>/src/lib/ui.js"
|
||||
],
|
||||
"transform": {
|
||||
"^.+\\.tsx?$": "ts-jest"
|
||||
},
|
||||
"testRegex": "(/test/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
|
||||
"coverageReporters": [
|
||||
"json",
|
||||
"lcov",
|
||||
"text-summary"
|
||||
],
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"jsx",
|
||||
"json",
|
||||
"node"
|
||||
],
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
"statements": 54,
|
||||
|
|
|
@ -2,28 +2,37 @@
|
|||
* This is the main entrypoint for the evergreen-client
|
||||
*/
|
||||
|
||||
const process = require('process');
|
||||
import feathers from '@feathersjs/feathers';
|
||||
import * as logger from 'winston';
|
||||
import socketio from '@feathersjs/socketio-client';
|
||||
import auth from '@feathersjs/authentication-client';
|
||||
import io from 'socket.io-client';
|
||||
|
||||
const feathers = require('@feathersjs/feathers');
|
||||
const logger = require('winston');
|
||||
const socketio = require('@feathersjs/socketio-client');
|
||||
const auth = require('@feathersjs/authentication-client');
|
||||
const io = require('socket.io-client');
|
||||
|
||||
const createCron = require('./lib/periodic');
|
||||
const ErrorTelemetry = require('./lib/error-telemetry');
|
||||
const HealthChecker = require('./lib/healthchecker');
|
||||
const Registration = require('./lib/registration');
|
||||
const Status = require('./lib/status');
|
||||
const Storage = require('./lib/storage');
|
||||
const UI = require('./lib/ui');
|
||||
const Update = require('./lib/update');
|
||||
import ErrorTelemetry from './lib/error-telemetry';
|
||||
import HealthChecker from './lib/healthchecker';
|
||||
import Registration from './lib/registration';
|
||||
import Status from './lib/status';
|
||||
import Storage from './lib/storage';
|
||||
import UI from './lib/ui'
|
||||
import Update from './lib/update';
|
||||
import Periodic from './lib/periodic';
|
||||
|
||||
/*
|
||||
* The Client class is a simple wrapper meant to start the basics of the client
|
||||
* and then run a simple runloop to block the client from ever exiting
|
||||
*/
|
||||
class Client {
|
||||
export default class Client {
|
||||
protected readonly app : any;
|
||||
protected readonly reg : Registration;
|
||||
protected readonly healthChecker : HealthChecker;
|
||||
protected readonly update : Update;
|
||||
protected readonly status : Status;
|
||||
protected readonly errorTelemetry : ErrorTelemetry;
|
||||
|
||||
protected socket : any;
|
||||
|
||||
public updating : boolean;
|
||||
|
||||
constructor() {
|
||||
if (!process.env.FLAVOR) {
|
||||
logger.error('Fatal error encountered while trying to start, no flavor set, exiting the client');
|
||||
|
@ -79,7 +88,7 @@ class Client {
|
|||
* Only setting on the cron once we have registered and logged in,
|
||||
* otherwise it's not really useful to have anything running periodically
|
||||
*/
|
||||
const cron = createCron(app);
|
||||
const cron = new Periodic();
|
||||
|
||||
this.runUpdates();
|
||||
|
||||
|
@ -151,7 +160,7 @@ class Client {
|
|||
this.runUpdates();
|
||||
});
|
||||
|
||||
this.reg.register().then((res, newRegistration) => {
|
||||
this.reg.register().then(({res, newRegistration}) => {
|
||||
UI.publish('Registered this Evergreen instance', { log: 'debug', error: res} );
|
||||
this.status.authenticate(this.reg.uuid, this.reg.token);
|
||||
this.update.authenticate(this.reg.uuid, this.reg.token);
|
||||
|
@ -168,8 +177,6 @@ class Client {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = Client;
|
||||
|
||||
if (require.main === module) {
|
||||
Storage.setBootingFlag();
|
||||
UI.serve();
|
||||
|
@ -180,6 +187,6 @@ if (require.main === module) {
|
|||
logger.level = process.env.LOG_LEVEL || 'warn';
|
||||
/* Main entrypoint for module */
|
||||
UI.publish('Starting the evergreen-client..', { log: 'info' });
|
||||
let client = new Client();
|
||||
const client = new Client();
|
||||
client.bootstrap();
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const logger = require('winston');
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
import * as logger from 'winston';
|
||||
|
||||
class Checksum {
|
||||
export default class Checksum {
|
||||
/*
|
||||
* Generate a SHA-256 checksum signature from the provided relative or
|
||||
* absolute file path
|
||||
|
@ -26,5 +26,3 @@ class Checksum {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Checksum;
|
|
@ -3,18 +3,19 @@
|
|||
* disk and checking them against provided checksums.
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
|
||||
const rp = require('promise-request-retry');
|
||||
const logger = require('winston');
|
||||
const mkdirp = require('mkdirp');
|
||||
import rp from 'promise-request-retry';
|
||||
import * as logger from 'winston';
|
||||
import mkdirp from 'mkdirp';
|
||||
|
||||
const Checksum = require('./checksum');
|
||||
const UI = require('./ui');
|
||||
import UI from './ui';
|
||||
import Checksum from './checksum';
|
||||
import { RequestOptions } from './request-options';
|
||||
|
||||
class Downloader {
|
||||
export default class Downloader {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
@ -40,7 +41,10 @@ class Downloader {
|
|||
* @param {string} the filename to output at
|
||||
* @parma {string} Optional sha256 signature to verify of the file
|
||||
*/
|
||||
static download(item, dir, fileNameToWrite, sha256, downloadOptions = {}) {
|
||||
static download(item, dir,
|
||||
fileNameToWrite?: string,
|
||||
sha256?: string,
|
||||
downloadOptions: RequestOptions = {}) {
|
||||
const itemUrl = url.parse(item);
|
||||
const itemUrlBaseName = path.basename(itemUrl.pathname);
|
||||
|
||||
|
@ -113,5 +117,3 @@ class Downloader {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Downloader;
|
|
@ -5,13 +5,24 @@
|
|||
* handle both error and "metrics" telemetry, but let's start with a smaller
|
||||
* scope at least for now.
|
||||
*/
|
||||
const { Tail } = require('tail');
|
||||
const fs = require('fs');
|
||||
const logger = require('winston');
|
||||
const path = require('path');
|
||||
const Storage = require('./storage');
|
||||
import { Tail } from 'tail';
|
||||
import fs from 'fs';
|
||||
import * as logger from 'winston'
|
||||
import path from 'path';
|
||||
|
||||
import Storage from './storage';
|
||||
|
||||
export interface ErrorTelemetryOptions {
|
||||
flavor?: string,
|
||||
};
|
||||
|
||||
export default class ErrorTelemetry {
|
||||
protected readonly app : any;
|
||||
protected readonly options : ErrorTelemetryOptions;
|
||||
|
||||
public uuid : string;
|
||||
public token : string;
|
||||
|
||||
class ErrorTelemetry {
|
||||
constructor(app, options) {
|
||||
this.app = app;
|
||||
this.options = options;
|
||||
|
@ -45,7 +56,7 @@ class ErrorTelemetry {
|
|||
* monitoredFile: path to the log file to watch
|
||||
* outputFunction(app,line): the function that will be called on each new line detected
|
||||
*/
|
||||
setup(monitoredFile) {
|
||||
setup(monitoredFile?: string) {
|
||||
logger.info('Setting up error logging...');
|
||||
let loggingFile = monitoredFile || this.fileToWatch();
|
||||
|
|
@ -1,12 +1,21 @@
|
|||
const logger = require('winston');
|
||||
const rp = require('promise-request-retry');
|
||||
|
||||
import * as logger from 'winston'
|
||||
import rp from 'promise-request-retry';
|
||||
|
||||
import { RequestOptions } from './request-options';
|
||||
|
||||
const INSTANCE_IDENTITY_URL = '/instance-identity/';
|
||||
const METRICS_URL = '/metrics/evergreen/healthcheck';
|
||||
|
||||
class HealthChecker {
|
||||
export default class HealthChecker {
|
||||
protected readonly defaultRequestOptions : any;
|
||||
|
||||
constructor(jenkinsRootUrl, requestOptions = {}) {
|
||||
public readonly jenkinsRootUrl : string;
|
||||
public readonly retry : number;
|
||||
public readonly delay : number;
|
||||
public readonly factor : number;
|
||||
|
||||
constructor(jenkinsRootUrl, requestOptions: RequestOptions = {}) {
|
||||
this.jenkinsRootUrl = jenkinsRootUrl;
|
||||
// let's target ~3 to 5 minutes overall of attempts for updates to arrive + Jenkins to start
|
||||
// TODO: later, introduce some smarter delay depending on the number of things to download?
|
||||
|
@ -111,5 +120,3 @@ class HealthChecker {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HealthChecker;
|
|
@ -4,16 +4,17 @@
|
|||
*
|
||||
*/
|
||||
|
||||
const logger = require('winston');
|
||||
const cron = require('cron');
|
||||
import * as logger from 'winston'
|
||||
import cron from 'cron';
|
||||
|
||||
export default class Periodic {
|
||||
protected readonly jobs : any;
|
||||
protected readonly offset : number;
|
||||
|
||||
class Periodic {
|
||||
/*
|
||||
* Requires the feathersjs app instance on initialization
|
||||
*/
|
||||
constructor (app, options) {
|
||||
this.app = app;
|
||||
this.options = options || {};
|
||||
constructor() {
|
||||
this.jobs = {};
|
||||
this.offset = this.computeOffset();
|
||||
logger.info('Periodic using minute offset of', this.offset);
|
||||
|
@ -48,8 +49,3 @@ class Periodic {
|
|||
return Math.floor(Math.random() * 59);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function(app, options) {
|
||||
return new Periodic(app, options);
|
||||
};
|
||||
module.exports.Periodic = Periodic;
|
|
@ -6,8 +6,8 @@
|
|||
* It seems to not believe that we're in nodejs when we really are
|
||||
*/
|
||||
|
||||
const crypto = require('crypto');
|
||||
const rand = require('brorand');
|
||||
import crypto from 'crypto';
|
||||
import rand from 'brorand';
|
||||
|
||||
rand.Rand.prototype._rand = function _rand(n) {
|
||||
return crypto.randomBytes(n);
|
|
@ -3,20 +3,35 @@
|
|||
* of the evergreen-client with the backend services layer
|
||||
*/
|
||||
|
||||
const ecc = require('elliptic');
|
||||
const fs = require('fs');
|
||||
const logger = require('winston');
|
||||
const path = require('path');
|
||||
const mkdirp = require('mkdirp');
|
||||
import ecc from 'elliptic';
|
||||
import * as logger from 'winston';
|
||||
import path from 'path';
|
||||
import mkdirp from 'mkdirp'
|
||||
import fs from 'fs';
|
||||
|
||||
const storage = require('./storage');
|
||||
import Storage from './storage';
|
||||
|
||||
require('./rand-patch');
|
||||
|
||||
class Registration {
|
||||
constructor (app, options) {
|
||||
export interface FileOptions {
|
||||
encoding?: string,
|
||||
flag?: string,
|
||||
};
|
||||
|
||||
export default class Registration {
|
||||
protected readonly app : any;
|
||||
protected readonly options : Map<string, any>;
|
||||
protected readonly curve : string;
|
||||
|
||||
protected privateKey : string;
|
||||
protected publicKey : string;
|
||||
protected fileOptions : FileOptions;
|
||||
|
||||
public uuid : string;
|
||||
public token : string;
|
||||
|
||||
constructor(app) {
|
||||
this.app = app;
|
||||
this.options = options || {};
|
||||
this.uuid = null;
|
||||
this.publicKey = null;
|
||||
this.privateKey = null;
|
||||
|
@ -46,15 +61,19 @@ class Registration {
|
|||
* @return Promise
|
||||
*/
|
||||
async register() {
|
||||
let self = this;
|
||||
const self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
let api = self.app.service('registration');
|
||||
const api = self.app.service('registration');
|
||||
logger.info('Checking registration status..');
|
||||
if (self.hasKeys() && self.hasUUID()) {
|
||||
logger.info('We have keys and a UUID already');
|
||||
self.loadKeysSync();
|
||||
self.loadUUIDSync();
|
||||
return self.login().then(res => resolve(res, false));
|
||||
return self.login().then(res => resolve(
|
||||
{
|
||||
result: res,
|
||||
created: false,
|
||||
}));
|
||||
} else {
|
||||
if (!self.generateKeys()) {
|
||||
return reject('Failed to generate keys');
|
||||
|
@ -72,7 +91,10 @@ class Registration {
|
|||
if (!self.saveUUIDSync()) {
|
||||
reject('Failed to save UUID!');
|
||||
} else {
|
||||
return self.login().then(res => resolve(res, true));
|
||||
return self.login().then(res => resolve({
|
||||
result: res,
|
||||
created: true,
|
||||
}));
|
||||
}
|
||||
}).catch((res) => {
|
||||
logger.error('Failed to register:', res);
|
||||
|
@ -108,8 +130,8 @@ class Registration {
|
|||
* @return Boolean
|
||||
*/
|
||||
generateKeys() {
|
||||
let ec = new ecc.ec(this.curve);
|
||||
let privkey = ec.genKeyPair();
|
||||
const ec = new ecc.ec(this.curve);
|
||||
const privkey = ec.genKeyPair();
|
||||
this.publicKey = privkey.getPublic('hex');
|
||||
this.privateKey = privkey.getPrivate('hex');
|
||||
|
||||
|
@ -126,7 +148,7 @@ class Registration {
|
|||
*
|
||||
* Will return null if no public key has yet been generated
|
||||
*
|
||||
* @return String
|
||||
* @return string
|
||||
*/
|
||||
getPublicKey() {
|
||||
return this.publicKey;
|
||||
|
@ -154,7 +176,7 @@ class Registration {
|
|||
}
|
||||
|
||||
loadUUIDSync() {
|
||||
let config = JSON.parse(fs.readFileSync(this.uuidPath(), this.fileOptions));
|
||||
const config = JSON.parse(fs.readFileSync(this.uuidPath(), this.fileOptions) as string);
|
||||
this.uuid = config.uuid;
|
||||
return (!!this.uuid);
|
||||
}
|
||||
|
@ -215,8 +237,8 @@ class Registration {
|
|||
if (!this.hasKeys()) {
|
||||
return false;
|
||||
}
|
||||
this.publicKey = fs.readFileSync(this.publicKeyPath(), this.fileOptions);
|
||||
this.privateKey = fs.readFileSync(this.privateKeyPath(), this.fileOptions);
|
||||
this.publicKey = fs.readFileSync(this.publicKeyPath(), this.fileOptions) as string;
|
||||
this.privateKey = fs.readFileSync(this.privateKeyPath(), this.fileOptions) as string;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -240,10 +262,10 @@ class Registration {
|
|||
|
||||
/* Return the directory where registration keys should be stored
|
||||
*
|
||||
* @return String
|
||||
* @return string
|
||||
*/
|
||||
keyPath() {
|
||||
const keys = path.join(storage.homeDirectory(), 'keys');
|
||||
const keys = path.join(Storage.homeDirectory(), 'keys');
|
||||
|
||||
/* Only bother making the directory if it doesn't already exist */
|
||||
try {
|
||||
|
@ -263,7 +285,7 @@ class Registration {
|
|||
*
|
||||
* This public key is safe to be shared with external services
|
||||
*
|
||||
* @return String
|
||||
* @return string
|
||||
*/
|
||||
publicKeyPath() {
|
||||
return path.join(this.keyPath(), 'evergreen.pub');
|
||||
|
@ -277,5 +299,3 @@ class Registration {
|
|||
return path.join(this.keyPath(), 'uuid.json');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Registration;
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
export interface RequestOptions {
|
||||
retry?: number,
|
||||
delay?: number,
|
||||
factor?: number,
|
||||
};
|
|
@ -4,9 +4,9 @@
|
|||
* https://github.com/jenkinsci/jep/tree/master/jep/302
|
||||
*/
|
||||
|
||||
const { spawnSync } = require('child_process');
|
||||
const logger = require('winston');
|
||||
const fs = require('fs');
|
||||
import { spawnSync } from 'child_process';
|
||||
import * as logger from 'winston';
|
||||
import fs from 'fs';
|
||||
|
||||
const LOG_PREFIX = '[snapshotting]';
|
||||
// https://github.com/jenkinsci/jep/tree/master/jep/302#user-content-files-to-store
|
||||
|
@ -16,10 +16,10 @@ const GITIGNORE_CONTENT = `
|
|||
/secrets/master.key
|
||||
`;
|
||||
|
||||
class Snapshotter {
|
||||
export default class Snapshotter {
|
||||
protected workingDirectory : string;
|
||||
|
||||
constructor(app, options) {
|
||||
this.options = options || {};
|
||||
constructor() {
|
||||
}
|
||||
|
||||
/**
|
|
@ -1,20 +1,30 @@
|
|||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
const logger = require('winston');
|
||||
const Storage = require('./storage');
|
||||
const Checksum = require('./checksum');
|
||||
import * as logger from 'winston';
|
||||
import Storage from './storage';
|
||||
import Checksum from './checksum';
|
||||
|
||||
|
||||
export interface StatusOptions {
|
||||
flavor?: string,
|
||||
};
|
||||
|
||||
/*
|
||||
* The status module is responsible for collecting and reporting the current
|
||||
* state of this instance to the Evergreen backend `Status` service
|
||||
*/
|
||||
class Status {
|
||||
constructor(app, options) {
|
||||
this.options = options || {};
|
||||
export default class Status {
|
||||
protected readonly app : any;
|
||||
protected readonly options : StatusOptions;
|
||||
|
||||
public uuid : string;
|
||||
public token : string;
|
||||
|
||||
constructor(app : any, options : StatusOptions = {}) {
|
||||
this.options = options;
|
||||
this.token = null;
|
||||
this.uuid = null;
|
||||
this.app = app;
|
||||
|
@ -38,8 +48,8 @@ class Status {
|
|||
* Create a status record in the backend for this particular instance
|
||||
*/
|
||||
async create() {
|
||||
let api = this.app.service('status');
|
||||
let record = {
|
||||
const api = this.app.service('status');
|
||||
const record = {
|
||||
uuid: this.uuid,
|
||||
flavor: this.options.flavor,
|
||||
timezone: this.getTimezone(),
|
||||
|
@ -68,8 +78,8 @@ class Status {
|
|||
}
|
||||
|
||||
reportLevel(updateLevel) {
|
||||
let api = this.app.service('status');
|
||||
let record = {
|
||||
const api = this.app.service('status');
|
||||
const record = {
|
||||
uuid: this.uuid,
|
||||
updateId: updateLevel,
|
||||
};
|
||||
|
@ -152,10 +162,6 @@ class Status {
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Status;
|
|
@ -1,15 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const logger = require('winston');
|
||||
const UI = require('./ui');
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import * as logger from 'winston';
|
||||
import UI from './ui';
|
||||
|
||||
/*
|
||||
* The Storage module simply contains common functions necessary for the
|
||||
* evergreen-client to store its own data.
|
||||
*/
|
||||
class Storage {
|
||||
export default class Storage {
|
||||
/*
|
||||
* Returns the default home directory or the value of EVERGREEN_HOME
|
||||
*
|
||||
|
@ -69,12 +70,12 @@ class Storage {
|
|||
}
|
||||
}
|
||||
|
||||
static removePlugins(plugins) {
|
||||
static removePlugins(plugins?: Array<any>) {
|
||||
if (!plugins) {
|
||||
return;
|
||||
}
|
||||
let pluginPath = this.pluginsDirectory();
|
||||
let retArray = [];
|
||||
const pluginPath = this.pluginsDirectory();
|
||||
const retArray = [];
|
||||
plugins.forEach((plugin) => {
|
||||
retArray.push(fs.unlink(`${pluginPath}/${plugin}.hpi`, () => {
|
||||
logger.info(`${pluginPath}/${plugin}.hpi was deleted`);
|
||||
|
@ -84,5 +85,3 @@ class Storage {
|
|||
return retArray;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Storage;
|
|
@ -3,15 +3,18 @@
|
|||
* XML-RPC API: http://supervisord.org/api.html
|
||||
*/
|
||||
|
||||
const xmlrpc = require('xmlrpc');
|
||||
const client = xmlrpc.createClient('http://localhost:9001/RPC2');
|
||||
const logger = require('winston');
|
||||
import xmlrpc from 'xmlrpc';
|
||||
import * as logger from 'winston'
|
||||
|
||||
const client = xmlrpc.createClient('http://localhost:9001/RPC2');
|
||||
|
||||
export default class Supervisord {
|
||||
protected readonly client : xmlrpc.Client;
|
||||
|
||||
class Supervisord {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
isRunning() {
|
||||
static isRunning() {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.methodCall('supervisor.getState', null, (e, v) => {
|
||||
if (e) {
|
||||
|
@ -22,7 +25,7 @@ class Supervisord {
|
|||
});
|
||||
}
|
||||
|
||||
printState(name) {
|
||||
static printState(name) {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.methodCall('supervisor.getProcessInfo', [name], (e, value) => {
|
||||
if (e) {
|
||||
|
@ -33,7 +36,7 @@ class Supervisord {
|
|||
});
|
||||
}
|
||||
|
||||
isProcessRunning(name) {
|
||||
static isProcessRunning(name) {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.methodCall('supervisor.getProcessInfo', [name], (e, value) => {
|
||||
if (e) {
|
||||
|
@ -44,7 +47,7 @@ class Supervisord {
|
|||
});
|
||||
}
|
||||
|
||||
startProcess(name) {
|
||||
static startProcess(name) {
|
||||
logger.info(`[supervisord] Starting ${name} process`);
|
||||
return new Promise((resolve, reject) => {
|
||||
client.methodCall('supervisor.startProcess', [name], (e, value) => {
|
||||
|
@ -56,7 +59,7 @@ class Supervisord {
|
|||
});
|
||||
}
|
||||
|
||||
stopProcess(name) {
|
||||
static stopProcess(name) {
|
||||
logger.info(`[supervisord] Stopping ${name} process`);
|
||||
return new Promise((resolve, reject) => {
|
||||
client.methodCall('supervisor.stopProcess', [name], (e, value) => {
|
||||
|
@ -68,7 +71,7 @@ class Supervisord {
|
|||
});
|
||||
}
|
||||
|
||||
async restartProcess(name) {
|
||||
static async restartProcess(name) {
|
||||
logger.info(`[supervisord] Restarting ${name} process`);
|
||||
if (await this.isProcessRunning(name)) {
|
||||
await this.stopProcess(name);
|
||||
|
@ -76,5 +79,3 @@ class Supervisord {
|
|||
return this.startProcess(name);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Supervisord();
|
|
@ -14,6 +14,9 @@ const logger = require('winston');
|
|||
* Simple shim feathers service just to enable events
|
||||
*/
|
||||
class MessageService {
|
||||
protected readonly app : any;
|
||||
protected recent : Array<any>;
|
||||
|
||||
constructor(app) {
|
||||
this.app = app;
|
||||
this.recent = [];
|
||||
|
@ -37,6 +40,9 @@ class MessageService {
|
|||
}
|
||||
|
||||
class UI {
|
||||
protected readonly app : any;
|
||||
protected server : any;
|
||||
|
||||
constructor() {
|
||||
const app = express(feathers());
|
||||
this.app = app;
|
||||
|
@ -60,7 +66,7 @@ class UI {
|
|||
* necessarily be presented to the user.
|
||||
*
|
||||
*/
|
||||
publish(message, params) {
|
||||
publish(message, params?: any) {
|
||||
return this.app.service('messages').create({
|
||||
message: message,
|
||||
timestamp: Date.now(),
|
||||
|
@ -75,4 +81,4 @@ class UI {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = new UI();
|
||||
export default new UI();
|
|
@ -4,26 +4,38 @@
|
|||
* https://github.com/jenkinsci/jep/tree/master/jep/307
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const mkdirp = require('mkdirp');
|
||||
const logger = require('winston');
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import mkdirp from 'mkdirp';
|
||||
import * as logger from 'winston';
|
||||
|
||||
const Downloader = require('./downloader');
|
||||
const HealthChecker = require('./healthchecker');
|
||||
const Storage = require('./storage');
|
||||
const Supervisord = require('./supervisord');
|
||||
const UI = require('./ui');
|
||||
const Snapshotter = require('./snapshotter');
|
||||
import Downloader from './downloader';
|
||||
import HealthChecker from './healthchecker';
|
||||
import Storage from './storage';
|
||||
import Supervisord from './supervisord';
|
||||
import UI from './ui';
|
||||
import Snapshotter from './snapshotter';
|
||||
|
||||
class Update {
|
||||
constructor(app, options) {
|
||||
this.options = options || {};
|
||||
export interface FileOptions {
|
||||
encoding?: string,
|
||||
flag?: string,
|
||||
};
|
||||
|
||||
export default class Update {
|
||||
protected readonly app : any;
|
||||
protected readonly snapshotter : Snapshotter;
|
||||
protected readonly fileOptions : FileOptions;
|
||||
protected readonly options : any;
|
||||
protected readonly healthChecker : HealthChecker;
|
||||
|
||||
public uuid : string;
|
||||
public token : string;
|
||||
public manifest : any;
|
||||
public updateInProgress : Date;
|
||||
|
||||
constructor(app, options = {}) {
|
||||
this.app = app;
|
||||
this.token = null;
|
||||
this.uuid = null;
|
||||
this.manifest = null;
|
||||
this.updateInProgress = null;
|
||||
this.options = options;
|
||||
this.fileOptions = { encoding: 'utf8' };
|
||||
this.snapshotter = new Snapshotter();
|
||||
this.snapshotter.init(Storage.jenkinsHome());
|
||||
|
@ -84,7 +96,7 @@ class Update {
|
|||
UI.publish('Starting to apply updates');
|
||||
// Setting this to a timestamp to make a timeout in the future
|
||||
this.updateInProgress = new Date();
|
||||
let tasks = [];
|
||||
const tasks = [];
|
||||
|
||||
if ((updates.core) && (updates.core.url)) {
|
||||
tasks.push(Downloader.download(updates.core.url,
|
||||
|
@ -150,7 +162,7 @@ class Update {
|
|||
while it's not been yet marked as tainted in the backend?
|
||||
* how to report that borked case in a clear way
|
||||
*/
|
||||
restartJenkins(rollingBack) { // Add param to stop recursion?
|
||||
restartJenkins(rollingBack?: boolean) { // Add param to stop recursion?
|
||||
Supervisord.restartProcess('jenkins');
|
||||
|
||||
const messageWhileRestarting = 'Jenkins should now be online, health checking!';
|
||||
|
@ -207,7 +219,7 @@ class Update {
|
|||
getCurrentLevel() {
|
||||
this.loadUpdateSync();
|
||||
if (this.manifest) {
|
||||
let level = this.manifest.meta.level;
|
||||
const level = this.manifest.meta.level;
|
||||
logger.silly('Currently at Update Level %d', level);
|
||||
return level;
|
||||
}
|
||||
|
@ -235,7 +247,7 @@ class Update {
|
|||
}
|
||||
}
|
||||
this.manifest = JSON.parse(fs.readFileSync(this.updatePath(),
|
||||
this.fileOptions));
|
||||
this.fileOptions) as string);
|
||||
return this.manifest;
|
||||
}
|
||||
|
||||
|
@ -260,5 +272,3 @@ class Update {
|
|||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Update;
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
jest.mock('fs');
|
||||
|
||||
const fs = require('fs');
|
||||
const Checksum = require('../src/lib/checksum');
|
||||
const fs = require('fs');
|
||||
|
||||
import Checksum from '../src/lib/checksum';
|
||||
|
||||
describe('Checksum', () => {
|
||||
beforeEach(() => {
|
|
@ -1,13 +1,12 @@
|
|||
const assert = require('assert');
|
||||
const tmp = require('tmp');
|
||||
const Client = require('../src/client');
|
||||
const Storage = require('../src/lib/storage');
|
||||
const mkdirp = require('mkdirp');
|
||||
|
||||
describe('The base client module', () => {
|
||||
import tmp from 'tmp';
|
||||
import Client from '../src/client';
|
||||
import Storage from '../src/lib/storage';
|
||||
|
||||
describe('The base client module', () => {
|
||||
it('should interpret properly', () => {
|
||||
assert(Client);
|
||||
expect(Client).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('flavorCheck', () => {
|
|
@ -2,8 +2,9 @@ jest.mock('fs');
|
|||
|
||||
const fs = require('fs');
|
||||
const mkdirp = require('mkdirp');
|
||||
const Downloader = require('../src/lib/downloader');
|
||||
const Checksum = require('../src/lib/checksum');
|
||||
|
||||
import Downloader from '../src/lib/downloader';
|
||||
import Checksum from '../src/lib/checksum';
|
||||
|
||||
describe('the Downloader class', () => {
|
||||
describe('download()', () => {
|
||||
|
@ -63,8 +64,9 @@ describe('the Downloader class', () => {
|
|||
await Downloader.download(toDownload, dir, 'thefile', null, {delay: 20, retry: 4, factor: 10});
|
||||
expect(false).toBeTruthy(); // fail(), should not reach this line.
|
||||
} catch (e) {
|
||||
const endTime = new Date();
|
||||
// 4 attempts, no delay for the first, then 20 ms, 20*10 (exponential factor), 20*10*10
|
||||
expect(new Date() - startTime).toBeGreaterThan(0 + 20 + 200 + 2000);
|
||||
expect((endTime as any) - (startTime as any)).toBeGreaterThan(0 + 20 + 200 + 2000);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -5,7 +5,7 @@ const fs = require('fs');
|
|||
const path = require('path');
|
||||
const mkdirp = require('mkdirp');
|
||||
|
||||
const ErrorTelemetry = require('../src/lib/error-telemetry');
|
||||
import ErrorTelemetry from '../src/lib/error-telemetry';
|
||||
|
||||
describe('Error Telemetry Logging', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -15,13 +15,13 @@ describe('Error Telemetry Logging', () => {
|
|||
|
||||
describe('authenticate()', () => {
|
||||
it('should store values', () => {
|
||||
const telemetry = new ErrorTelemetry().authenticate('you-you-i-Dee', 'toe-ken-that-guy');
|
||||
const telemetry = new ErrorTelemetry(null, null).authenticate('you-you-i-Dee', 'toe-ken-that-guy');
|
||||
assert.equal(telemetry.uuid, 'you-you-i-Dee');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup() call', () => {
|
||||
const errorTelemetryService = new ErrorTelemetry();
|
||||
const errorTelemetryService = new ErrorTelemetry(null, null);
|
||||
|
||||
let logsDir = '/evergreen/jenkins/war/logs';
|
||||
let logFile = path.join(logsDir, 'evergreen.log.0');
|
|
@ -1,7 +1,8 @@
|
|||
const HealthChecker = require('../src/lib/healthchecker');
|
||||
const logger = require('winston');
|
||||
const http = require('http');
|
||||
|
||||
import HealthChecker from '../src/lib/healthchecker';
|
||||
|
||||
describe('The healthchecker module', () => {
|
||||
let server = null;
|
||||
let port = -1;
|
||||
|
@ -13,17 +14,19 @@ describe('The healthchecker module', () => {
|
|||
instanceIdentity: true,
|
||||
metrics: {
|
||||
plugins: true,
|
||||
deadlock: true
|
||||
}
|
||||
deadlock: true,
|
||||
body: null,
|
||||
},
|
||||
};
|
||||
|
||||
describe('constructor', () => {
|
||||
it('should use default values if none passed in', () => {
|
||||
const healthChecker = new HealthChecker();
|
||||
const healthChecker = new HealthChecker('http://example.com');
|
||||
expect(healthChecker.retry).toEqual(25);
|
||||
expect(healthChecker.delay).toEqual(3000);
|
||||
expect(healthChecker.factor).toEqual(1.10);
|
||||
});
|
||||
|
||||
it('should use passed in values', () => {
|
||||
const jenkinsRootUrl = `http://localhost:${port}`;
|
||||
const requestOptions = {delay: 100, retry: 1, factor: 1.01};
|
||||
|
@ -35,7 +38,7 @@ describe('The healthchecker module', () => {
|
|||
});
|
||||
it('should override the delay if env var set', () => {
|
||||
const retryOverride = 21;
|
||||
process.env.PROCESS_RETRY_OVERRIDE = retryOverride;
|
||||
process.env.PROCESS_RETRY_OVERRIDE = retryOverride.toString();
|
||||
const jenkinsRootUrl = `http://localhost:${port}`;
|
||||
const requestOptions = {delay: 100, retry: 1, factor: 1.01};
|
||||
const healthChecker = new HealthChecker(jenkinsRootUrl, requestOptions);
|
||||
|
@ -45,7 +48,7 @@ describe('The healthchecker module', () => {
|
|||
expect(healthChecker.factor).toEqual(requestOptions.factor);
|
||||
});
|
||||
it('should handle non int value in env var', () => {
|
||||
process.env.PROCESS_RETRY_OVERRIDE = true;
|
||||
process.env.PROCESS_RETRY_OVERRIDE = 'true';
|
||||
const jenkinsRootUrl = `http://localhost:${port}`;
|
||||
const requestOptions = {delay: 100, retry: 1, factor: 1.01};
|
||||
const healthChecker = new HealthChecker(jenkinsRootUrl, requestOptions);
|
|
@ -1,33 +0,0 @@
|
|||
const assert = require('assert');
|
||||
const periodic = require('../src/lib/periodic');
|
||||
|
||||
describe('The periodic module', () => {
|
||||
/* Just a simple fake app for unit test
|
||||
*/
|
||||
let app = new Object();
|
||||
|
||||
describe('runHourly()', () => {
|
||||
it('allow registration of an hourly callback', () => {
|
||||
let p = periodic(app);
|
||||
assert.ok(p.runHourly('jest-fun', () => { }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('runDaily()', () => {
|
||||
it('allows registration of a daily callback', () => {
|
||||
let p = periodic(app);
|
||||
assert.ok(p.runDaily('jest-fun', () => { }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('computeOffset()', () => {
|
||||
let p = periodic(app);
|
||||
|
||||
it('should return a number between 0-59', () => {
|
||||
let offset = p.computeOffset();
|
||||
assert.equal(typeof offset, 'number');
|
||||
assert.ok(offset <= 59);
|
||||
assert.ok(offset >= 0);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
import Periodic from '../src/lib/periodic';
|
||||
|
||||
describe('The periodic module', () => {
|
||||
/* Just a simple fake app for unit test
|
||||
*/
|
||||
describe('runHourly()', () => {
|
||||
it('allow registration of an hourly callback', () => {
|
||||
const p = new Periodic();
|
||||
expect(p.runHourly('jest-fun', () => {})).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('runDaily()', () => {
|
||||
it('allows registration of a daily callback', () => {
|
||||
const p = new Periodic();
|
||||
expect(p.runDaily('jest-fun', () => {})).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('computeOffset()', () => {
|
||||
const p = new Periodic();
|
||||
|
||||
it('should return a number between 0-59', () => {
|
||||
const offset = p.computeOffset();
|
||||
expect(offset).toBeGreaterThanOrEqual(0);
|
||||
expect(offset).toBeLessThanOrEqual(59);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -3,9 +3,11 @@ jest.mock('fs');
|
|||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const Registration = require('../src/lib/registration');
|
||||
|
||||
import Registration from '../src/lib/registration';
|
||||
|
||||
describe('The registration module', () => {
|
||||
const app = new Object();
|
||||
beforeEach(() => {
|
||||
/* Make sure memfs is flushed every time */
|
||||
fs.volume.reset();
|
||||
|
@ -13,19 +15,19 @@ describe('The registration module', () => {
|
|||
|
||||
describe('register()', () => {
|
||||
it('should return a Promise', () => {
|
||||
const response = (new Registration()).register();
|
||||
const response = (new Registration(app)).register();
|
||||
assert(response instanceof Promise);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPublicKey()', () => {
|
||||
it('should return null on a new instance', () => {
|
||||
const r = new Registration();
|
||||
const r = new Registration(app);
|
||||
assert.equal(null, r.getPublicKey());
|
||||
});
|
||||
|
||||
it('should return a public key after generateKeys() has been called', () => {
|
||||
const r = new Registration();
|
||||
const r = new Registration(app);
|
||||
assert(r.generateKeys());
|
||||
assert.equal(typeof r.getPublicKey(), 'string');
|
||||
});
|
||||
|
@ -33,7 +35,7 @@ describe('The registration module', () => {
|
|||
|
||||
describe('saveUUIDSync()', () => {
|
||||
beforeEach(() => {
|
||||
this.reg = new Registration();
|
||||
this.reg = new Registration(app);
|
||||
});
|
||||
it('should not write anything by default', () => {
|
||||
assert.equal(this.reg.saveUUIDSync(), false);
|
||||
|
@ -62,7 +64,7 @@ describe('The registration module', () => {
|
|||
describe('loadUUIDSync()', () => {
|
||||
let uuid = 'just another-fake-uuid';
|
||||
beforeEach(() => {
|
||||
this.reg = new Registration();
|
||||
this.reg = new Registration(app);
|
||||
this.reg.uuid = uuid;
|
||||
this.reg.saveUUIDSync();
|
||||
});
|
||||
|
@ -76,13 +78,13 @@ describe('The registration module', () => {
|
|||
|
||||
describe('saveKeysSync()', () => {
|
||||
it('should return false if there are not keys', () => {
|
||||
const r = new Registration();
|
||||
const r = new Registration(app);
|
||||
assert(!r.saveKeysSync());
|
||||
});
|
||||
|
||||
describe('when keys have been generated', () => {
|
||||
beforeEach(() => {
|
||||
this.reg = new Registration();
|
||||
this.reg = new Registration(app);
|
||||
this.reg.generateKeys();
|
||||
});
|
||||
it('should return true if the public key has been written', () => {
|
||||
|
@ -107,7 +109,7 @@ describe('The registration module', () => {
|
|||
|
||||
describe('loadKeysSync()', () => {
|
||||
beforeEach(() => {
|
||||
this.reg = new Registration();
|
||||
this.reg = new Registration(app);
|
||||
});
|
||||
|
||||
it('should return false by default when there are no keys', () => {
|
||||
|
@ -121,7 +123,7 @@ describe('The registration module', () => {
|
|||
|
||||
describe('when keys are already on disk', () => {
|
||||
beforeEach(() => {
|
||||
const preflight = new Registration();
|
||||
const preflight = new Registration(app);
|
||||
preflight.generateKeys();
|
||||
preflight.saveKeysSync();
|
||||
});
|
||||
|
@ -135,31 +137,31 @@ describe('The registration module', () => {
|
|||
|
||||
describe('hasKeys()', () => {
|
||||
it('should return false by default', () => {
|
||||
assert.equal((new Registration()).hasKeys(), false);
|
||||
assert.equal((new Registration(app)).hasKeys(), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateKeys()', () => {
|
||||
it('should return a boolean on success', () => {
|
||||
assert.ok((new Registration()).generateKeys());
|
||||
assert.ok((new Registration(app)).generateKeys());
|
||||
});
|
||||
});
|
||||
|
||||
describe('publicKeyPath()', () => {
|
||||
it('should return a path', () => {
|
||||
const p = (new Registration()).publicKeyPath();
|
||||
const p = (new Registration(app)).publicKeyPath();
|
||||
assert(p != path.basename(p), 'This doesn\'t look like a path');
|
||||
});
|
||||
});
|
||||
|
||||
describe('keyPath()', () => {
|
||||
it('should return a path', () => {
|
||||
const keys = (new Registration()).keyPath();
|
||||
const keys = (new Registration(app)).keyPath();
|
||||
assert(keys != path.basename(keys), 'This doesn\'t look like a path');
|
||||
});
|
||||
|
||||
it('should create a directory if one does not exist', () => {
|
||||
const keyPath = (new Registration()).keyPath();
|
||||
const keyPath = (new Registration(app)).keyPath();
|
||||
const stats = fs.statSync(keyPath);
|
||||
assert(stats.isDirectory());
|
||||
});
|
||||
|
@ -176,7 +178,7 @@ describe('The registration module', () => {
|
|||
|
||||
describe('uuidPath()', () => {
|
||||
it('should return a path', () => {
|
||||
const p = (new Registration()).uuidPath();
|
||||
const p = (new Registration(app)).uuidPath();
|
||||
assert(p != path.basename(p), 'This doesn\'t look like a path');
|
||||
});
|
||||
});
|
|
@ -1,10 +1,10 @@
|
|||
const Snapshotter = require('../src/lib/snapshotter');
|
||||
const tmp = require('tmp');
|
||||
const fs = require('fs');
|
||||
|
||||
describe('The snapshotting module', () => {
|
||||
import tmp from 'tmp';
|
||||
import Snapshotter from '../src/lib/snapshotter';
|
||||
|
||||
let tmpDir = '';
|
||||
describe('The snapshotting module', () => {
|
||||
let tmpDir = null;
|
||||
beforeEach(() => {
|
||||
tmpDir = tmp.dirSync({unsafeCleanup: true});
|
||||
});
|
|
@ -5,7 +5,8 @@ jest.mock('fs');
|
|||
const fs = require('fs');
|
||||
const mkdirp = require('mkdirp');
|
||||
const feathers = require('@feathersjs/feathers');
|
||||
const Status = require('../src/lib/status');
|
||||
|
||||
import Status from '../src/lib/status';
|
||||
|
||||
describe('The status module', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -57,7 +58,7 @@ describe('The status module', () => {
|
|||
|
||||
describe('collectVersions()', () => {
|
||||
it('should contain a node version', () => {
|
||||
const versions = (new Status(app)).collectVersions();
|
||||
const versions : any = (new Status(app)).collectVersions();
|
||||
expect(versions.container.tools.node).toBeTruthy();
|
||||
});
|
||||
|
||||
|
@ -80,7 +81,7 @@ describe('The status module', () => {
|
|||
});
|
||||
|
||||
it('should contain the signature of the plugin', () => {
|
||||
const versions = (new Status(app)).collectVersions();
|
||||
const versions : any = (new Status(app)).collectVersions();
|
||||
expect(versions.jenkins.plugins.git).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -3,8 +3,9 @@ jest.mock('fs');
|
|||
const fs = require('fs');
|
||||
const mkdirp = require('mkdirp');
|
||||
const path = require('path');
|
||||
const h = require('./helpers');
|
||||
const Storage = require('../src/lib/storage');
|
||||
|
||||
import h from '../testlib/helpers';
|
||||
import Storage from '../src/lib/storage';
|
||||
|
||||
describe('The storage module', () => {
|
||||
let dir = '/tmp';
|
|
@ -1,4 +1,5 @@
|
|||
const UI = require('../src/lib/ui');
|
||||
|
||||
import UI from '../src/lib/ui';
|
||||
|
||||
describe('The UI module', () => {
|
||||
it('should be a singleton', () => {
|
|
@ -1,17 +1,19 @@
|
|||
jest.mock('../src/lib/supervisord');
|
||||
jest.mock('../src/lib/downloader');
|
||||
|
||||
const tmp = require('tmp');
|
||||
const fs = require('fs');
|
||||
const feathers = require('@feathersjs/feathers');
|
||||
const h = require('./helpers');
|
||||
const Update = require('../src/lib/update');
|
||||
const HealthChecker = require('../src/lib/healthchecker');
|
||||
const Storage = require('../src/lib/storage');
|
||||
const Supervisord = require('../src/lib/supervisord');
|
||||
const Downloader = require('../src/lib/downloader');
|
||||
const mkdirp = require('mkdirp');
|
||||
|
||||
import tmp from 'tmp';
|
||||
import h from '../testlib/helpers';
|
||||
|
||||
import Update from '../src/lib/update';
|
||||
import HealthChecker from '../src/lib/healthchecker';
|
||||
import Storage from '../src/lib/storage';
|
||||
import Supervisord from '../src/lib/supervisord';
|
||||
import Downloader from '../src/lib/downloader';
|
||||
|
||||
describe('The update module', () => {
|
||||
let app = null;
|
||||
let update = null;
|
||||
|
@ -124,7 +126,7 @@ describe('The update module', () => {
|
|||
|
||||
it ('should execute updates if passed in with no deletes', async () => {
|
||||
jest.setTimeout(10000);
|
||||
Downloader.mockImplementationOnce(() => {
|
||||
(Downloader as unknown as jest.Mock).mockImplementationOnce(() => {
|
||||
return require.requireActual('../src/lib/downloader').default();
|
||||
});
|
||||
|
||||
|
@ -146,7 +148,7 @@ describe('The update module', () => {
|
|||
});
|
||||
|
||||
it('should execute both updates and deletes if both passed in', async () => {
|
||||
Downloader.mockImplementationOnce(() => {
|
||||
(Downloader as unknown as jest.Mock).mockImplementationOnce(() => {
|
||||
return require.requireActual('../src/lib/downloader').default();
|
||||
});
|
||||
manifest.plugins.deletes = ['delete1'];
|
|
@ -8,7 +8,7 @@ const open = promisify(fs.open);
|
|||
const close = promisify(fs.close);
|
||||
const access = promisify(fs.access);
|
||||
|
||||
class Helpers {
|
||||
export class Helpers {
|
||||
constructor () {
|
||||
}
|
||||
|
||||
|
@ -23,4 +23,4 @@ class Helpers {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = new Helpers();
|
||||
export default new Helpers();
|
|
@ -5,7 +5,7 @@
|
|||
"outDir": "./build",
|
||||
"module" : "commonjs",
|
||||
"skipLibCheck": true,
|
||||
"lib" : ["es2017"],
|
||||
"lib" : ["es2015"],
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
|
|
Loading…
Reference in New Issue