From 8ea37cfdb58c3cc2cb06e2fce22c82af454e8855 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Mon, 21 Sep 2020 20:47:26 +0300 Subject: [PATCH] feature: fetch metadata for latest server version --- src/interfaces/appstore.js | 11 +-- src/{modules.test.js => modules.test.ts} | 103 ++++++++++++++--------- src/modules.ts | 49 ++++++++--- 3 files changed, 107 insertions(+), 56 deletions(-) rename src/{modules.test.js => modules.test.ts} (61%) diff --git a/src/interfaces/appstore.js b/src/interfaces/appstore.js index 5f9eca958..a7e1b91c5 100644 --- a/src/interfaces/appstore.js +++ b/src/interfaces/appstore.js @@ -21,7 +21,7 @@ const { installModule, removeModule } = require('../modules') const { isTheServerModule, findModulesWithKeyword, - getLatestServerVersion, + getLatestServerVersionInfo, getAuthor, getKeywords } = require('../modules') @@ -125,9 +125,9 @@ module.exports = function(app) { app.get(`${SERVERROUTESPREFIX}/appstore/available/`, (req, res) => { findPluginsAndWebapps() .then(([plugins, webapps]) => { - getLatestServerVersion(app.config.version) - .then(serverVersion => { - const result = getAllModuleInfo(plugins, webapps, serverVersion) + getLatestServerVersionInfo(app.config.version) + .then(({ version }) => { + const result = getAllModuleInfo(plugins, webapps, version) res.send(JSON.stringify(result)) }) .catch(err => { @@ -189,7 +189,8 @@ module.exports = function(app) { installing: [], categories: getAvailableCategories(), storeAvailable: true, - isInDocker: process.env.IS_IN_DOCKER === 'true' + isInDocker: process.env.IS_IN_DOCKER === 'true', + nodeVersion: {} } } diff --git a/src/modules.test.js b/src/modules.test.ts similarity index 61% rename from src/modules.test.js rename to src/modules.test.ts index 97036caa5..835e817d8 100644 --- a/src/modules.test.js +++ b/src/modules.test.ts @@ -1,12 +1,12 @@ -const chai = require('chai') -const _ = require('lodash') -const fs = require('fs') -const path = require('path') -const { - modulesWithKeyword, +import chai from 'chai' +import fs from 'fs' +import _ from 'lodash' +import path from 'path' +import { checkForNewServerVersion, - getLatestServerVersion -} = require('./modules') + getLatestServerVersionInfo, + modulesWithKeyword +} from './modules' describe('modulesWithKeyword', () => { it('returns a list of modules with one "installed" update in config dir', () => { @@ -26,6 +26,7 @@ describe('modulesWithKeyword', () => { const app = { config: { + name: 'dummy-name-in-test', appPath: path.join(__dirname + '/../'), configPath: testTempDir } @@ -61,6 +62,11 @@ describe('modulesWithKeyword', () => { }) describe('checkForNewServerVersion', () => { + const newMinorVersionInfo = { + version: '1.18.0', + disttag: 'latest', + minimumNodeVersion: '10' + } it('normal version upgrade', done => { checkForNewServerVersion( '1.17.0', @@ -68,77 +74,102 @@ describe('checkForNewServerVersion', () => { if (err) { done(err) } else { - chai.expect(newVersion).to.equal('1.18.0') + chai.expect(newVersion).to.equal(newMinorVersionInfo.version) done() } }, - () => Promise.resolve('1.18.0') + () => Promise.resolve(newMinorVersionInfo) ) }) it('normal version does not upgrade to beta', done => { + const newBetaVersion = { + version: '1.18.0-beta.2', + disttag: 'latest', + minimumNodeVersion: '10' + } checkForNewServerVersion( '1.17.0', err => { done('callback should not be called') }, - () => Promise.resolve('1.18.0-beta.1') + () => Promise.resolve(newBetaVersion) ) done() }) it('beta upgrades to same minor newer beta', done => { + const newerBetaVersionInfo = { + version: '1.18.0-beta.2', + disttag: 'latest', + minimumNodeVersion: '10' + } checkForNewServerVersion( '1.18.0-beta.1', (err, newVersion) => { if (err) { done(err) } else { - chai.expect(newVersion).to.equal('1.18.0-beta.2') + chai.expect(newVersion).to.equal(newerBetaVersionInfo.version) done() } }, - () => Promise.resolve('1.18.0-beta.2') + () => Promise.resolve(newerBetaVersionInfo) ) }) it('beta upgrades to same normal version', done => { + const sameNormalVersion = { + version: '1.18.0', + disttag: 'latest', + minimumNodeVersion: '10' + } checkForNewServerVersion( '1.18.0-beta.2', (err, newVersion) => { if (err) { done(err) } else { - chai.expect(newVersion).to.equal('1.18.0') + chai.expect(newVersion).to.equal(sameNormalVersion.version) done() } }, - () => Promise.resolve('1.18.0') + () => Promise.resolve(sameNormalVersion) ) }) it('beta upgrades to newer normal version', done => { + const newerNormalVersion = { + version: '1.19.0', + disttag: 'latest', + minimumNodeVersion: '10' + } checkForNewServerVersion( '1.18.0-beta.2', (err, newVersion) => { if (err) { done(err) } else { - chai.expect(newVersion).to.equal('1.19.0') + chai.expect(newVersion).to.equal(newerNormalVersion.version) done() } }, - () => Promise.resolve('1.19.0') + () => Promise.resolve(newerNormalVersion) ) }) it('beta does not upgrade to newer minor beta', done => { + const nextMinorBetaVersion = { + version: '1.18.0-beta.2', + disttag: 'latest', + minimumNodeVersion: '10' + } checkForNewServerVersion( '1.17.0-beta.1', err => { done('callback should not be called') }, - () => Promise.resolve('1.18.0-beta.2') + () => Promise.resolve(nextMinorBetaVersion) ) done() }) @@ -146,42 +177,36 @@ describe('checkForNewServerVersion', () => { describe('getLatestServerVersion', () => { it('latest for normal is normal', () => { - return getLatestServerVersion('1.17.0', () => + return getLatestServerVersionInfo('1.17.0', () => Promise.resolve({ - json: () => ({ - latest: '1.18.3', - beta: '1.19.0-beta.1' - }) + latest: '1.18.0', + beta: '1.19.0-beta.1' }) - ).then(newVersion => { - chai.expect(newVersion).to.equal('1.18.3') + ).then(newVersionInfo => { + chai.expect(newVersionInfo.version).to.equal('1.18.0') }) }) it('latest for beta is newer same series beta', done => { - getLatestServerVersion('1.18.0-beta.2', () => + getLatestServerVersionInfo('1.18.0-beta.2', () => Promise.resolve({ - json: () => ({ - latest: '1.17.3', - beta: '1.18.0-beta.3' - }) + latest: '1.17.3', + beta: '1.18.0-beta.3' }) - ).then(newVersion => { - chai.expect(newVersion).to.equal('1.18.0-beta.3') + ).then(newVersionInfo => { + chai.expect(newVersionInfo.version).to.equal('1.18.0-beta.3') done() }) }) it('latest for beta is newer real release', () => { - return getLatestServerVersion('1.18.0-beta.2', () => + return getLatestServerVersionInfo('1.18.0-beta.2', () => Promise.resolve({ - json: () => ({ - latest: '1.18.0', - beta: '1.18.0-beta.3' - }) + latest: '1.18.0', + beta: '1.18.0-beta.3' }) - ).then(newVersion => { - chai.expect(newVersion).to.equal('1.18.0') + ).then(newVersionInfo => { + chai.expect(newVersionInfo.version).to.equal('1.18.0') }) }) }) diff --git a/src/modules.ts b/src/modules.ts index 74d59c8e1..c06a083c7 100644 --- a/src/modules.ts +++ b/src/modules.ts @@ -110,7 +110,7 @@ const priorityPrefix = (a: ModuleData, b: ModuleData) => getModuleSortName(a).localeCompare(getModuleSortName(b)) // Searches for installed modules that contain `keyword`. -function modulesWithKeyword(app: App, keyword: string) { +export function modulesWithKeyword(app: App, keyword: string) { return _.uniqBy( // _.flatten since values are inside an array. [[modules...], [modules...]] _.flatten( @@ -265,33 +265,58 @@ function findModulesWithKeyword(keyword: string) { } function doFetchDistTags() { - return fetch('http://registry.npmjs.org/-/package/signalk-server/dist-tags') + return fetch( + 'http://registry.npmjs.org/-/package/signalk-server/dist-tags' + ).then(r => r.json()) } -function getLatestServerVersion( +export interface ServerVersionInfo { + version: string + disttag: string + minimumNodeVersion: string +} + +export function getLatestServerVersionInfo( currentVersion: string, distTags = doFetchDistTags -): Promise { +): Promise { return new Promise((resolve, reject) => { distTags() - .then(npmjsResults => npmjsResults.json()) .then(npmjsParsed => { const prereleaseData = semver.prerelease(currentVersion) if (prereleaseData) { if (semver.satisfies(npmjsParsed.latest, `>${currentVersion}`)) { - resolve(npmjsParsed.latest) + return [npmjsParsed.latest, 'latest'] } else { - resolve(npmjsParsed[prereleaseData[0]]) + return [npmjsParsed[prereleaseData[0]], 'beta'] } } else { - resolve(npmjsParsed.latest) + return [npmjsParsed.latest, 'latest'] } }) + .then(([version, disttag]) => { + return fetch('https://registry.npmjs.org/signalk-server', { + headers: { + Accept: 'application/vnd.npm.install-v1+json' + } + }) + .then(res => res.json()) + .then(json => { + return json + }) + .then(moduleMetadata => { + resolve({ + version, + disttag, + minimumNodeVersion: `${moduleMetadata.versions[version].engines}` + }) + }) + }) .catch(reject) }) } -function checkForNewServerVersion( +export function checkForNewServerVersion( currentVersion: string, serverUpgradeIsAvailable: ( errMessage: string | void, @@ -299,10 +324,10 @@ function checkForNewServerVersion( ) => any, getLatestServerVersionP: ( version: string - ) => Promise = getLatestServerVersion + ) => Promise = getLatestServerVersionInfo ) { getLatestServerVersionP(currentVersion) - .then((version: string) => { + .then(({ version }) => { if (semver.satisfies(new SemVer(version), `>${currentVersion}`)) { serverUpgradeIsAvailable(undefined, version) } @@ -342,7 +367,7 @@ module.exports = { removeModule, isTheServerModule, findModulesWithKeyword, - getLatestServerVersion, + getLatestServerVersionInfo, checkForNewServerVersion, getAuthor, getKeywords,