Skip to content

Commit

Permalink
refactor: Enable triage process to run @serverless/compose (#10950)
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrzesik committed Apr 14, 2022
1 parent 82ce1c8 commit 401c721
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 2 deletions.
9 changes: 8 additions & 1 deletion bin/serverless.js
Expand Up @@ -41,7 +41,6 @@ if (isMainModule) {

const path = require('path');
const localInstallationPath = require('../lib/cli/local-serverless-path');

if (localInstallationPath && localInstallationPath !== path.dirname(__dirname)) {
// Local fallback
const localServerlessBinPath = (() => {
Expand Down Expand Up @@ -73,6 +72,14 @@ require('../lib/cli/triage')().then((cliName) => {
case 'serverless':
require('../scripts/serverless');
return;
case '@serverless/compose':
require('../lib/cli/run-compose')().catch((error) => {
// Expose eventual resolution error as regular crash, and not unhandled rejection
process.nextTick(() => {
throw error;
});
});
return;
case 'serverless-tencent':
require('../lib/cli/run-serverless-tencent')().catch((error) => {
// Expose eventual resolution error as regular crash, and not unhandled rejection
Expand Down
134 changes: 134 additions & 0 deletions lib/cli/run-compose.js
@@ -0,0 +1,134 @@
'use strict';

const { createRequire } = require('module');
const path = require('path');
const fsp = require('fs').promises;
const spawn = require('child-process-ext/spawn');
const inquirer = require('@serverless/utils/inquirer');

const relativeBinPath = '@serverless/compose/bin/serverless-compose';

const ensureMinimalPackageJson = async () => {
return fsp.writeFile(path.join(process.cwd(), 'package.json'), '{}');
};

const resolveAbsoluteModulePath = (contextDirname, modulePath) => {
try {
return createRequire(path.resolve(contextDirname, 'require-resolver')).resolve(modulePath);
} catch {
return null;
}
};

const resolveGlobalNpmPath = async () => {
const npmNodeModulesPath = await (async () => {
try {
return String((await spawn('npm', ['root', '-g'])).stdoutBuffer).trim();
} catch (error) {
return null;
}
})();

if (!npmNodeModulesPath) return null;
try {
return require.resolve(`${npmNodeModulesPath}/${relativeBinPath}`);
} catch (globalDepError) {
return null;
}
};

module.exports = async () => {
// 1. If installed locally in service node_modules, run it
const localNpmPath = resolveAbsoluteModulePath(process.cwd(), relativeBinPath);
if (localNpmPath) {
require(localNpmPath);
return;
}

// 2. If installed as npm global installation, run it
const globalNpmPath = await resolveGlobalNpmPath();
if (globalNpmPath) {
require(globalNpmPath);
return;
}

process.stdout.write(
`${['', 'Serverless Compose needs to be installed first. This is a one-time operation.'].join(
'\n'
)}\n`
);

let hasPackageJson = false;
try {
await fsp.access('package.json');
hasPackageJson = true;
} catch {
// Pass
}

let promptMessage = 'Do you want to install Serverless Compose locally with "npm"?';
if (!hasPackageJson) {
promptMessage += ' A "package.json" file will also be created in your current directory.';
}

const shouldInstallCompose = (
await inquirer.prompt({
message: promptMessage,
type: 'confirm',
name: 'shouldInstallCompose',
})
).shouldInstallCompose;

// Add progress bar
if (shouldInstallCompose) {
const getCliProgressFooter = require('cli-progress-footer');
const cliProgressFooter = getCliProgressFooter();
cliProgressFooter.shouldAddProgressAnimationPrefix = true;
cliProgressFooter.progressAnimationPrefixFrames =
cliProgressFooter.progressAnimationPrefixFrames.map((frame) => `\x1b[91m${frame}\x1b[39m`);

cliProgressFooter.updateProgress('Installing Serverless Compose CLI');

try {
if (!hasPackageJson) {
try {
await ensureMinimalPackageJson();
} catch {
process.stdout.write(
`${[
'',
'Could not create "package.json" in current directory.',
'Please create it manually and run this command again.',
].join('\n')}\n`
);
return;
}
}

try {
await spawn('npm', ['install', '--save-dev', '@serverless/compose']);
} catch {
process.stdout.write(
`${[
'',
'Could not install Serverless Compose CLI locally.',
'Please install it manually with "npm i --save-dev @serverless/compose" and run this command again.',
].join('\n')}\n`
);
return;
}
} finally {
cliProgressFooter.updateProgress();
}
// Try to run local compose
const installedLocalNpmPath = resolveAbsoluteModulePath(process.cwd(), relativeBinPath);
require(installedLocalNpmPath);
} else {
process.stdout.write(
`${[
'',
'Please install it manually with "npm i --save-dev @serverless/compose" and run this command again.',
].join('\n')}\n`
);
}
};
17 changes: 17 additions & 0 deletions lib/cli/triage.js
Expand Up @@ -47,6 +47,23 @@ module.exports = async () => {
return resolvePlatformCli();
}

if (
(
await Promise.all(
['yml', 'yaml', 'json', 'js', 'ts'].map(async (extension) => {
try {
await fsp.access(`serverless-compose.${extension}`);
return true;
} catch {
return false;
}
})
)
).some(Boolean)
) {
return '@serverless/compose';
}

// Detect eventual service configuration
const configurationExtension =
(
Expand Down
@@ -0,0 +1,10 @@
'use strict';

module.exports = {
name: 'serverless-compose-example',
services: {
resources: {
path: 'resources',
},
},
};
@@ -0,0 +1,8 @@
{
"name": "serverless-compose-example",
"services": {
"resources": {
"path": "resources"
}
}
}
@@ -0,0 +1,8 @@
module.exports = {
"name": "serverless-compose-example",
"services": {
"resources": {
"path": "resources"
}
}
}
@@ -0,0 +1,16 @@
name: serverless-compose-example

services:
resources:
path: resources

producer:
path: producer
params:
workerQueueArn: ${resources.WorkerQueueArn}
workerQueueUrl: ${resources.WorkerQueueUrl}

consumer:
path: consumer
params:
workerQueueArn: ${resources.WorkerQueueArn}
@@ -0,0 +1,16 @@
name: serverless-compose-example

services:
resources:
path: resources

producer:
path: producer
params:
workerQueueArn: ${resources.WorkerQueueArn}
workerQueueUrl: ${resources.WorkerQueueUrl}

consumer:
path: consumer
params:
workerQueueArn: ${resources.WorkerQueueArn}
2 changes: 1 addition & 1 deletion test/unit/lib/cli/triage/index.test.js
Expand Up @@ -57,7 +57,7 @@ describe('test/unit/lib/cli/triage/index.test.js', () => {
});
after(() => restoreArgv());

for (const cliName of ['serverless', '@serverless/cli']) {
for (const cliName of ['serverless', '@serverless/cli', '@serverless/compose']) {
for (const extension of fs.readdirSync(path.resolve(fixturesDirname, cliName))) {
for (const fixtureName of fs.readdirSync(
path.resolve(fixturesDirname, cliName, extension)
Expand Down

0 comments on commit 401c721

Please sign in to comment.