Skip to content

Commit

Permalink
Dev Experience Improvement - Phase 2 (#330)
Browse files Browse the repository at this point in the history
* Improved fdk user, login and extension preview command

* show organization name in fdk user and login command

* Removed fdk preview api-key related code

* fdk extension preview port is now optional

* Fixed test cases

* port required test case removed

* Readme.md updated

* Updated Error messages
- Directly pick extension API key from .env file if present in fdk extension preview command
- Improved error message where updateLaunchURL API failed
- Fixed test cases related to updateLaunchURL error message fix
- FDK cli new version available message updated
- fdk login command success message updated for better readability

* Updated development company creation url in error message of fdk extension preview command

- Updated error message as per review commands

* Updated template names in fdk extension init command

* Updated error messages in fdk extension init and setup command

---------

Co-authored-by: vivek-gofynd <[email protected]>
  • Loading branch information
bhargavprajapatiFynd and vivek-gofynd authored Jul 17, 2024
1 parent 318a173 commit 2dfb5b6
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 59 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gofynd/fdk-cli",
"version": "5.1.3",
"version": "5.1.4",
"main": "index.js",
"license": "MIT",
"bin": {
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/previewUrlExtension.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ describe('Extension preview-url command', () => {
configStore.set(CONFIG_KEYS.NGROK_AUTHTOKEN, AUTH_TOKEN);
mockCustomAxios
.onPatch(`${URLS.UPDATE_EXTENSION_DETAILS_PARTNERS(EXTENSION_KEY)}`)
.reply(404, {});
.reply(404, {message: "not found"});
jest.spyOn(inquirer, 'prompt').mockResolvedValueOnce({
ngrok_authtoken: 'auth_token',
});
Expand Down Expand Up @@ -258,7 +258,7 @@ describe('Extension preview-url command', () => {
it('Should throw an error for partner access token for lower versions than v1.9.2 to update base url of extension', async () => {
mockAxios
.onPatch(`${URLS.UPDATE_EXTENSION_DETAILS_PARTNERS(EXTENSION_KEY)}`)
.reply(404, {});
.reply(404, {message: "not found"});
configStore.set(CONFIG_KEYS.AUTH_TOKEN, LOGIN_AUTH_TOKEN);
configStore.set(CONFIG_KEYS.NGROK_AUTHTOKEN, AUTH_TOKEN);

Expand Down
12 changes: 6 additions & 6 deletions src/fdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,17 @@ Command.prototype.asyncAction = async function (asyncFn: Action) {
const major = versionChange === 'major';
const color = major ? 'red' : 'green';

const logMessage = `There is a new version of ${
packageJSON.name
} available (${latest}).
You are currently using ${packageJSON.name} ${packageJSON.version}.
Install fdk-cli globally using the package manager of your choice.
const logMessage = `A new version ${latest} is available!.
You have version ${packageJSON.version}.
Please update to the latest version.
${
major
? `\nNote: You need to update \`${packageJSON.name}\` first inorder to use it.`
: ''
}
Run \`npm install -g ${packageJSON.name}\` to get the latest version.`;
Run the following command to upgrade:
\`npm install -g ${packageJSON.name}\``;

if (
allowed_update_version_types.includes(versionChange) &&
Expand Down
25 changes: 16 additions & 9 deletions src/lib/Auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,21 @@ export const getApp = async () => {
req.body.auth_token.expiry_time = expiryTimestamp;
ConfigStore.set(CONFIG_KEYS.AUTH_TOKEN, req.body.auth_token);
ConfigStore.set(CONFIG_KEYS.ORGANIZATION, req.body.organization);
const organization_detail = await OrganizationService.getOrganizationDetails();
ConfigStore.set(CONFIG_KEYS.ORGANIZATION_DETAIL, organization_detail.data);
const organization_detail =
await OrganizationService.getOrganizationDetails();
ConfigStore.set(
CONFIG_KEYS.ORGANIZATION_DETAIL,
organization_detail.data,
);
Auth.stopSever();
if (Auth.isOrganizationChange)
Logger.info('Organization changed successfully');
else Logger.info('User logged in successfully');
Logger.info(`New Organization: ${getOrganizationDisplayName()}`);
Logger.info(
`Logged in successfully in organization ${getOrganizationDisplayName()}`,
);
res.status(200).json({ message: 'success' });
} catch (err) {
Debug(err);
Auth.stopSever();
res.status(500).json({ message: 'failed'})
res.status(500).json({ message: 'failed' });
}
});

Expand Down Expand Up @@ -88,7 +91,9 @@ export default class Auth {
const isLoggedIn = await Auth.isAlreadyLoggedIn();
await startServer();
if (isLoggedIn) {
Logger.info(`Current logged in organization: ${getOrganizationDisplayName()}`);
Logger.info(
`Current logged in organization: ${getOrganizationDisplayName()}`,
);
const questions = [
{
type: 'list',
Expand Down Expand Up @@ -168,7 +173,9 @@ export default class Auth {
'Not primary email set';
Logger.info(`Name: ${user.first_name} ${user.last_name}`);
Logger.info(`Email: ${activeEmail}`);
Logger.info(`Current organization: ${getOrganizationDisplayName()}`);
Logger.info(
`Current organization: ${getOrganizationDisplayName()}`,
);
} catch (error) {
throw new CommandError(error.message, error.code);
}
Expand Down
26 changes: 15 additions & 11 deletions src/lib/Extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import execa from 'execa';
import rimraf from 'rimraf';
import which from 'which';

import { getPlatformUrls } from './api/services/url';
import Spinner from '../helper/spinner';
import CommandError, { ErrorCodes } from './CommandError';
import ExtensionService, {
Expand All @@ -28,13 +29,14 @@ import {
installPythonDependencies,
} from '../helper/utils';
import Logger from './Logger';
import urljoin from 'url-join';

export const NODE_VUE = 'Node + Vue.js';
export const NODE_REACT = 'Node + React.js';
export const PYTHON_VUE = 'Python + Vue.js';
export const PYTHON_REACT = 'Python + React.js';
export const JAVA_VUE = 'Java + Vue.js';
export const JAVA_REACT = 'Java + React.js';
export const NODE_VUE = 'Node + Vue.js + Redis';
export const NODE_REACT = 'Node + React.js + Redis';
export const PYTHON_VUE = 'Python + Vue.js + Redis';
export const PYTHON_REACT = 'Python + React.js + Redis';
export const JAVA_VUE = 'Java + Vue.js + Redis';
export const JAVA_REACT = 'Java + React.js + Redis';

export const PROJECT_REPOS = {
[NODE_VUE]: 'https://github.com/gofynd/example-extension-javascript.git',
Expand Down Expand Up @@ -237,12 +239,14 @@ export default class Extension {
} catch (error) {
spinner.fail();
}

const organizationId = ConfigStore.get(CONFIG_KEYS.ORGANIZATION)
const createDevelopmentCompanyFormURL = organizationId ? urljoin(getPlatformUrls().partners, 'organizations', organizationId , 'extensions', 'overview', answers.extension_api_key) : getPlatformUrls().partners;
let text =
chalk.green.bold('DONE ') +
chalk.green.bold('Project ready\n') +
chalk.yellowBright.bold('NOTE: ') +
chalk.green.bold(`cd ${targetDir} to continue...`);
chalk.green.bold(`cd "${targetDir}" to continue...\n`) +
chalk.green.bold(`To manage your extension visit: ${createDevelopmentCompanyFormURL}`);

Logger.info(
boxen(text, { padding: 1, borderColor: 'greenBright' }),
Expand Down Expand Up @@ -330,7 +334,7 @@ export default class Extension {
],
default: NODE_VUE,
name: 'project_type',
message: 'Development Language :',
message: 'Template :',
validate: validateEmpty,
},
{
Expand Down Expand Up @@ -369,7 +373,7 @@ export default class Extension {
private static checkFolderAndGitExists(folderPath: string) {
if (fs.existsSync(folderPath)) {
throw new CommandError(
`Folder at "${path}" already exists. Please choose another name or directory.`,
`Directory "${folderPath}" is already exists in current directory. Please choose another name or directory.`,
);
}
if (fs.existsSync(path.join(folderPath, '/.git'))) {
Expand Down Expand Up @@ -442,7 +446,7 @@ export default class Extension {
],
default: NODE_VUE,
name: 'project_type',
message: 'Development Language :',
message: 'Template :',
validate: validateEmpty,
},
{
Expand Down
16 changes: 9 additions & 7 deletions src/lib/ExtensionLaunchURL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default class ExtensionLaunchURL {
{ base_url: launch_url },
);
} catch (err) {
if (err.response.status === 404) {
if (err.response.status === 404 && err?.response?.data?.message === "not found") {
if (!partner_access_token) {
spinner.fail();
throw new CommandError(
Expand All @@ -63,7 +63,7 @@ export default class ExtensionLaunchURL {
);
}
} else {
throw new CommandError('Failed updating Launch Url');
throw new CommandError(err?.response?.data?.message || 'Failed updating Launch Url');
}
}

Expand All @@ -73,13 +73,15 @@ export default class ExtensionLaunchURL {
spinner.succeed();
console.log(
chalk.greenBright(
`Launch url set successfully${
manualUpdateRequired
? '. Please update launch url in your code.'
: ''
}`,
`Extension Launch url set successfully on Partners Panel`,
),
);
if(manualUpdateRequired){
console.log(
chalk.blueBright('\nPlease update extension launch url in your code.')
)
}

} catch (error) {
spinner.fail();
throw new CommandError(error.message);
Expand Down
76 changes: 55 additions & 21 deletions src/lib/ExtensionPreviewURL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import chalk from 'chalk';
import boxen from 'boxen';
import urljoin from 'url-join';
import inquirer from 'inquirer';
import path from 'path';
import fs from 'fs';

import Debug from './Debug';
import { getPlatformUrls } from './api/services/url';
Expand All @@ -14,6 +16,7 @@ import {
Object,
validateEmpty,
} from '../helper/extension_utils';
import { readFile } from '../helper/file.utils';
import Spinner from '../helper/spinner';
import CommandError, { ErrorCodes } from './CommandError';
import Logger from './Logger';
Expand Down Expand Up @@ -118,17 +121,11 @@ export default class ExtensionPreviewURL {
});

if (choices.length === 0) {
const organizationId = configStore.get(CONFIG_KEYS.ORGANIZATION)
const createDevelopmentCompanyFormURL = organizationId ? urljoin(getPlatformUrls().partners, 'organizations', organizationId , 'accounts') : getPlatformUrls().partners;
Logger.info(
chalk.yellowBright(
`You haven't created any development account in "${getOrganizationDisplayName()}" organization.`,
),
);

Logger.info(
chalk.yellowBright(
`Please create a development account from ${
getPlatformUrls().partners
} and try again`,
`You don't have development account under organization ${getOrganizationDisplayName()}, You can create development account from ${createDevelopmentCompanyFormURL} and try again.`
),
);

Expand Down Expand Up @@ -186,22 +183,59 @@ export default class ExtensionPreviewURL {

private async promptExtensionApiKey(): Promise<string> {
let extension_api_key: string;
try {
let answers = await inquirer.prompt([
{
type: 'input',
name: 'extension_api_key',
message: 'Enter Extension API Key :',
validate: validateEmpty,
},
]);
extension_api_key = answers.extension_api_key;
} catch (error) {
throw new CommandError(error.message);
const apiKeyFromEnv = this.getExtensionAPIKeyFromENV();
if(apiKeyFromEnv){
Logger.info(`Using Extension API key from environment : ${apiKeyFromEnv}`);
extension_api_key = apiKeyFromEnv
}
else{
try {
let answers = await inquirer.prompt([
{
type: 'input',
name: 'extension_api_key',
message: 'Enter Extension API Key :',
validate: validateEmpty,
},
]);
extension_api_key = answers.extension_api_key;
} catch (error) {
throw new CommandError(error.message);
}
}
return extension_api_key;
}

public getExtensionAPIKeyFromENV(){
let java_env_file_path = path.join(
'src',
'main',
'resources',
'application.yml',
);

if (fs.existsSync('./.env')) {
let envData = readFile('./.env');
const keyMatchRegex = new RegExp(`^\\s*EXTENSION_API_KEY\\s*=\\s*(?:'([^']*)'|"([^"]*)"|([^'"\s]+))`, 'm')
const match = keyMatchRegex.exec(envData);
if(match){
const value = (match[1] || match[2] || match[3]).trim();
return value === '' ? null : value;
}
} else if (fs.existsSync(java_env_file_path)) {
let envData = readFile(java_env_file_path);
const keyMatchRegex = new RegExp(`^\\s*api_key\\s*:\\s*(?:'([^']*)'|"([^"]*)"|([^'"\s]+))`, 'm')
const match = keyMatchRegex.exec(envData);
if(match){
const value = (match[1] || match[2] || match[3]).trim();
return value === '' ? null : value;
}
} else {
return null;
}
return null;
}

private async promptDevelopmentCompany(choices): Promise<number> {
let companyId: number;
try {
Expand Down

0 comments on commit 2dfb5b6

Please sign in to comment.