Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init nomo cli.config.js #3

Merged
merged 5 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 0 additions & 27 deletions nomo_cli.config.js

This file was deleted.

8 changes: 0 additions & 8 deletions out/nomo_manifest.json

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nomo-webon-cli",
"version": "0.1.1",
"version": "0.1.0",
"description": "A CLI for building and deploying Nomo WebOns",
"repository": {
"type": "git",
Expand Down
102 changes: 87 additions & 15 deletions src/init/init.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as fs from "fs";
import * as path from "path";
import { NomoManifest } from "./interface";
import { NomoManifest, NomoCliConfig, GeneratedFile } from "./interface";
import { isValidWebOnId } from "../util/validate-manifest";

async function getUserInput(prompt: string): Promise<string> {
// Import inquirer dynamically
const inquirer = require("inquirer");

const { userInput } = await (inquirer as any).prompt([
Expand All @@ -17,28 +17,100 @@ async function getUserInput(prompt: string): Promise<string> {
return userInput;
}

async function generateNomoManifestContent(
webonId: string,
webonName: string
): Promise<NomoManifest> {
return {
nomo_manifest_version: "1.1.0",
webon_id: webonId,
webon_name: webonName,
webon_version: "0.1.0",
permissions: [],
};
}

function generateNomoCliConfigContent(webonId: string): NomoCliConfig {
return {
deployTargets: {
production: {
rawSSH: {
sshHost: "root@<IP-address>",
sshBaseDir: `/var/www/production_webons/${webonId}/`,
publicBaseUrl: `https://w.nomo.app/${webonId}`,
},
},
staging: {
rawSSH: {
sshHost:
process.env.SSH_TARGET ||
"Set your env SSH_TARGET like: export SSH_TARGET= <value> ",
sshBaseDir: `/var/www/html/webons/${webonId}/`,
publicBaseUrl: `https://staging.nomo.app/${webonId}`,
sshPort: 51110,
},
},
},
};
}

function writeFile(file: GeneratedFile): void {
fs.writeFileSync(file.filePath, file.content);
console.log(`${path.basename(file.filePath)} created successfully.`);
}

export async function init(args: { assetDir: string }): Promise<void> {
const assetDir = args.assetDir;
const manifestFilePath = path.join(assetDir, "nomo_manifest.json");
const cliConfigFilePath = path.join(process.cwd(), "nomo_cli.config.js");

// Check if nomo_manifest.json already exists
if (fs.existsSync(manifestFilePath)) {
console.log("nomo_manifest.json already exists.");
} else {
// Prompt user for input
const webonId = await getUserInput("Enter webon_id: ");
const webonName = await getUserInput("Enter webon_name: ");
const webonId = await getValidWebOnId("Enter unique webon_id: ");

const nomoManifest = await generateNomoManifestContent(webonId, webonName);

writeFile({
filePath: manifestFilePath,
content: JSON.stringify(nomoManifest, null, 2),
});
}

// Check if nomo_cli.config.js already exists
if (fs.existsSync(cliConfigFilePath)) {
console.log("nomo_cli.config.js already exists.");
} else {
const nomoManifestContent = fs.readFileSync(manifestFilePath, "utf-8");
const nomoManifest: NomoManifest = JSON.parse(nomoManifestContent);

const webonId = nomoManifest.webon_id;
const nomoCliConfig = generateNomoCliConfigContent(webonId);

writeFile({
filePath: cliConfigFilePath,
content: `/**
* This is a sample configuration that can be adapted to your needs.
*/

const nomoCliConfig = ${JSON.stringify(nomoCliConfig, null, 2)};

module.exports = {
nomoCliConfig,
};`,
});
}
}

// Create nomo_manifest.json with user input
const nomoManifest: NomoManifest = {
nomo_manifest_version: "1.1.0",
webon_id: webonId,
webon_name: webonName,
webon_version: "0.1.0",
permissions: [],
};

fs.writeFileSync(manifestFilePath, JSON.stringify(nomoManifest, null, 2));
console.log("nomo_manifest.json created successfully.");
async function getValidWebOnId(prompt: string): Promise<string> {
let webonId = await getUserInput(prompt);
while (!isValidWebOnId(webonId)) {
console.error(`Invalid webon_id: ${webonId}`);
webonId = await getUserInput(
"Enter an unique valid webon_id like demo.web.app for example:"
);
}
return webonId;
}
97 changes: 60 additions & 37 deletions src/init/interface.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,61 @@
export interface NomoManifest {
/**
* If min_nomo_version is set, then outdated versions of the Nomo App will refuse to install the WebOn.
*/
min_nomo_version?: string | null;
/**
* nomo_manifest_version should be 1.1.0.
*/
nomo_manifest_version: string;
/**
* A list of permissions for security-critical features.
*/
permissions: string[];
/**
* webon_id should be the reverse-domain of a domain that is owned by the WebOn-author.
* See https://en.wikipedia.org/wiki/Reverse_domain_name_notation for more details about the reverse domain name notation.
*/
webon_id: string;
/**
* webon_name is the user-visible name of the WebOn.
*/
webon_name: string;
/**
* webon_version should comply with the semantic versioning standard.
* See https://semver.org/ for details.
*/
webon_version: string;
/**
* If true, then the WebOn could be displayed in both card-mode and fullscreen-mode.
* If false, then the WebOn will only be displayed in fullscreen-mode.
*/
card_mode?: boolean;
/**
* If defined, then the WebOn can decide whether a navigation bar should be shown or not.
*/
show_navbar?: boolean;
}

/**
* If min_nomo_version is set, then outdated versions of the Nomo App will refuse to install the WebOn.
*/
min_nomo_version?: string | null;
/**
* nomo_manifest_version should be 1.1.0.
*/
nomo_manifest_version: string;
/**
* A list of permissions for security-critical features.
*/
permissions: string[];
/**
* webon_id should be the reverse-domain of a domain that is owned by the WebOn-author.
* See https://en.wikipedia.org/wiki/Reverse_domain_name_notation for more details about the reverse domain name notation.
*/
webon_id: string;
/**
* webon_name is the user-visible name of the WebOn.
*/
webon_name: string;
/**
* webon_version should comply with the semantic versioning standard.
* See https://semver.org/ for details.
*/
webon_version: string;
/**
* If true, then the WebOn could be displayed in both card-mode and fullscreen-mode.
* If false, then the WebOn will only be displayed in fullscreen-mode.
*/
card_mode?: boolean;
/**
* If defined, then the WebOn can decide whether a navigation bar should be shown or not.
*/
show_navbar?: boolean;
}

export interface NomoCliConfig {
deployTargets: {
production: {
rawSSH: {
sshHost: string;
sshBaseDir: string;
publicBaseUrl: string;
};
};
staging: {
rawSSH: {
sshHost: string;
sshBaseDir: string;
publicBaseUrl: string;
sshPort: number;
};
};
};
}
export interface GeneratedFile {
filePath: string;
content: string;
}
75 changes: 75 additions & 0 deletions src/util/validate-manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { NomoManifest } from "../init/interface";

class WebOnError extends Error {
constructor(message: string) {
super(message);
this.name = "WebOnError";
}
}

async function validateManifest(
manifest: NomoManifest,
webonUrl: string,
{ devMode }: { devMode: boolean }
): Promise<void> {
const webonVersion = manifest.webon_version;
if (!_isValidSemanticVersion(webonVersion)) {
throw new WebOnError(
`webon_version ${webonVersion} does not comply with semantic versioning regexp`
);
}

const webonId = manifest.webon_id;
if (!isValidWebOnId(webonId)) {
throw new WebOnError(`webon_id ${webonId} does not comply with regexp`);
}

const manifestVersion = manifest.nomo_manifest_version;
if (!_isValidSemanticVersion(manifestVersion)) {
throw new WebOnError(
`nomo_manifest_version ${manifestVersion} does not comply with semantic versioning regexp`
);
}

if (manifest.webon_name.trim() == null) {
throw new WebOnError("webon_name is empty");
}

const minNomoVersion = manifest.min_nomo_version;
if (minNomoVersion != null) {
if (!_isValidSemanticVersion(minNomoVersion)) {
throw new WebOnError(
`min_nomo_version ${minNomoVersion} does not comply with semantic versioning regexp`
);
}
// Assume you have a function similar to versionTwoGreaterThanVersionOne
const currentVersion = "1.2.0"; // You need to replace this with the actual version
if (versionTwoGreaterThanVersionOne(currentVersion, minNomoVersion)) {
throw new WebOnError(
`Nomo App outdated! This WebOn requires ${minNomoVersion}, but the current version is ${currentVersion}`
);
}
}
}


function _isValidSemanticVersion(version: string): boolean {
const pattern = /^(\d+)\.(\d+)\.(\d+)$/;
const regex = new RegExp(pattern);
return regex.test(version);
}

// Assuming versionTwoGreaterThanVersionOne is a function you have implemented
function versionTwoGreaterThanVersionOne(
versionTwo: string,
versionOne: string
): boolean {
// Implement the comparison logic here
return false;
}

export function isValidWebOnId(webon_id: string): boolean {
const webonIdRegExp =
/^(?:[a-zA-Z0-9_-]+\.)*[a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)+$/;
return webonIdRegExp.test(webon_id);
}
Loading