Skip to content

Commit

Permalink
Merge pull request #8 from tago-io/fix/analysisRun
Browse files Browse the repository at this point in the history
Fix Analysis Run and Add Documentation
  • Loading branch information
vitorfdl authored Sep 21, 2023
2 parents 165dbba + 3dd26f9 commit 12244ff
Show file tree
Hide file tree
Showing 40 changed files with 798 additions and 272 deletions.
80 changes: 59 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,53 @@
<img src="https://assets.tago.io/tagoio/tagoio.png" width="200px" alt="TODO"></img>
</p>

# Table of Contents
- [TagoIO Command Line Tools](#tagoio-command-line-tools)
- [How to Install](#how-to-install)
- [Command List](#command-list)
- [Analysis Runner](#analysis-runner)
- [Credentials Storage](#credentials-storage)
- [tagoconfig.json](#tagoconfigjson)
- [Working with Environments](#working-with-environments)
- [License](#license)

For more information on the latest release notes, please visit the [Release Notes section](https://github.com/tago-io/tagoio-cli/releases)

## TagoIO Command Line Tools
This project is a CLI Tool to be used with TagoIO. It's main functionality is to help with deployment within multiple profiles, as well as providing useful tools for developers.
TagoIO Command Line Tools is a CLI tool that allows you to interact with TagoIO platform and manage your applications. You can use it to deploy, run, trigger, and debug your analysis, as well as to inspect, backup, and configure your devices. You can also export your applications from one profile to another.

To use this tool, you need to install it globally with npm and also install the builder dependency. You also need to generate a tagoconfig.json file for your project and a .tago-lock file for your profile. You can work with multiple environments by using the init and set-env commands.

To work with Analysis, the tool requires that you run **tagoio init** to generate a tagoconfig.json
For more information about the commands and options of this tool, please refer to the [Command List](#command-list) section.

![CLI Demo](./docs/images/tagoio_inspect.png)

To connect to Devices, the CLI only requires you to generate your profile-token with **tagoio login**

# How to Install
- Run **npm install -g @tago-io/cli** to install this package globally.
- Run **npm install -g @tago-io/builder** to install the builder dependecy.

Installing the TagoIO Command Line Tools is a straightforward process. Follow these steps to get started:

1. **Preparation**: Ensure that Node.js and npm are installed on your machine. If not, refer to the [installation guide](^1^).

2. **CLI Tool Installation**: Open your terminal and run the following command to install the CLI tool globally:
```sh
npm install -g @tago-io/cli
```

3. **Builder Dependency Installation**: Next, install the builder dependency using the command:
```sh
npm install -g @tago-io/builder
```

4. **Project Initialization**: Initialize your project by generating a `tagoconfig.json` file. Use the command below and follow the on-screen instructions to provide your credentials or profile-token (available in your TagoIO account):
```sh
tagoio init
```

5. **Profile Token Storage (Optional)**: To store your profile token in a `.tago-lock` file, use the `tagoio login` command. This step also allows you to work with different environments by adding an argument to the command:
```sh
tagoio login
```

## Command List
List of commands of the CLI
Expand Down Expand Up @@ -55,22 +92,11 @@ List of commands of the CLI
When writing up your analysis, make sure you have the following lines at end of the code:

```javascript
if (!process.env.T_TEST) {
Analysis.use(startAnalysis, { token: process.env.T_ANALYSIS_TOKEN });
}
Analysis.use(startAnalysis, { token: process.env.T_ANALYSIS_TOKEN });

export { startAnalysis };
```

When running tests, make sure to set T_TEST environment variable on your terminal.

If you want to use the Debugger with -D, make sure you have a **.swcrc** file with sourceMaps activated

```
{
"sourceMaps": true
}
```
If you want to use the Debugger with -D, make sure you have a **.swcrc** file with sourceMaps activated. This repository contains a .swcrc.example file if you prefer to just copy to your folder.

## Credentials Storage
When running **tagoio login** or **tagoio init**, the CLI will store your Profile-Token in the current folder on your terminal.
Expand All @@ -90,12 +116,24 @@ Having a tagoconfig.json is required in order to run the following cmds:
You will also be required to have the .tago-lock file for a given environment.



## Working with Environments
The CLI is optimized to work within multiple environments. That makes it easier to alternate environments for deployment and management of your analysis.

You can create new environments by running the **tagoio init** cmd.
Managing multiple environments is a breeze with the TagoIO CLI. This feature facilitates seamless alternation between different environments for deployment and analysis management. Here's how you can make the most of it:

You can change your current environment by running the **tagoio set-env** cmd.
### Creating a New Environment
To set up a new environment, use the `tagoio init` command. This will guide you through the necessary steps to establish a fresh environment for your project. Here's how you can do it:

```sh
tagoio init
```

### Switching Between Environments
If you are working with multiple environments, switching between them is essential. Use the `tagoio set-env` command to change your current environment effortlessly. Here's the command to use:

```sh
tagoio set-env [environment_name]
```

## License

Expand Down
Binary file added docs/images/tagoio_inspect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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": "@tago-io/cli",
"version": "1.5.0",
"version": "1.5.1",
"description": "TagoIO Application CLI Node.JS",
"main": "./build/index.js",
"repository": "tago-io/tagoio-cli",
Expand Down
83 changes: 58 additions & 25 deletions src/commands/analysis/analysis-console.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { Account } from "@tago-io/sdk";
import { connect } from "socket.io-client";

import { Account } from "@tago-io/sdk";

import { getEnvironmentConfig, IEnvironment } from "../../lib/config-file";
import { errorHandler, highlightMSG, infoMSG, successMSG } from "../../lib/messages";
import { searchName } from "../../lib/search-name";
import { pickAnalysisFromConfig } from "../../prompt/pick-analysis-from-config";

/**
* Creates a WebSocket connection to the TagoIO Realtime API.
* @param profileToken The user's profile token.
* @returns The WebSocket instance.
*/
function apiSocket(profileToken: string) {
const socket = connect("wss://realtime.tago.io", {
reconnectionDelay: 10_000,
Expand All @@ -18,41 +25,37 @@ function apiSocket(profileToken: string) {
return socket;
}

async function connectAnalysisConsole(scriptName: string | void, options: { environment: string }) {
const config = getEnvironmentConfig(options.environment);
if (!config || !config.profileToken) {
errorHandler("Environment not found");
return;
}
/**
* Returns the script object from the analysis list based on the script name or prompts the user to select one.
* @param scriptName - The name of the script to search for.
* @param analysisList - The list of analysis objects to search through.
* @returns The script object that matches the script name or the one selected by the user.
*/
async function getScriptObj(scriptName: string | void, analysisList: IEnvironment["analysisList"]) {
let scriptObj: IEnvironment["analysisList"][0] | undefined;
if (scriptName) {
scriptObj = searchName(
scriptName,
config.analysisList.map((x) => ({ names: [x.name, x.fileName], value: x }))
analysisList.map((x) => ({ names: [x.name, x.fileName], value: x }))
);
} else {
scriptObj = await pickAnalysisFromConfig(config.analysisList);
scriptObj = await pickAnalysisFromConfig(analysisList);
}

if (!scriptObj) {
errorHandler(`Analysis not found: ${scriptName}`);
return;
}

const account = new Account({ token: config.profileToken, region: "usa-1" });
const analysis_info = await account.analysis.info(scriptObj.id).catch(() => null);
if (!analysis_info) {
errorHandler(`Analysis with ID: ${scriptObj.id} couldn't be found.`);
return;
}

const socket = apiSocket(config.profileToken);
return scriptObj;
}
/**
* Sets up a socket connection to TagoIO and attaches to an analysis script.
* @param socket - The socket connection to TagoIO.
* @param scriptId - The ID of the analysis script to attach to.
* @param analysis_info - Information about the analysis script.
*/
function setupSocket(socket: ReturnType<typeof apiSocket>, scriptId: string, analysis_info: any) {
socket.on("connect", () => {
infoMSG("Connected to TagoIO, Getting analysis information...");
socket.emit("attach", "analysis", scriptObj?.id);
socket.emit("attach", "analysis", scriptId);
socket.emit("attach", {
resourceName: "analysis",
resourceID: scriptObj?.id,
resourceID: scriptId,
});
});

Expand All @@ -70,4 +73,34 @@ async function connectAnalysisConsole(scriptName: string | void, options: { envi
});
}

/**
* Connects to the analysis console for a given script name and environment.
* @param scriptName - The name of the script to connect to.
* @param options - The options object containing the environment to connect to.
* @returns void
*/
async function connectAnalysisConsole(scriptName: string | void, options: { environment: string }) {
const config = getEnvironmentConfig(options.environment);
if (!config || !config.profileToken) {
errorHandler("Environment not found");
return;
}

const scriptObj = await getScriptObj(scriptName, config.analysisList);
if (!scriptObj) {
errorHandler(`Analysis not found: ${scriptName}`);
return;
}

const account = new Account({ token: config.profileToken, region: "usa-1" });
const analysis_info = await account.analysis.info(scriptObj.id);
if (!analysis_info) {
errorHandler(`Analysis with ID: ${scriptObj.id} couldn't be found.`);
return;
}

const socket = apiSocket(config.profileToken);
setupSocket(socket, scriptObj.id, analysis_info);
}

export { connectAnalysisConsole };
83 changes: 59 additions & 24 deletions src/commands/analysis/analysis-set-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,58 +8,93 @@ import { errorHandler, infoMSG, successMSG } from "../../lib/messages";
import { chooseFromList } from "../../prompt/choose-from-list";
import { pickFromList } from "../../prompt/pick-from-list";

async function analysisSetMode(userInputName: string | void, options: { environment: string; mode: string; filterMode: string }) {
const config = getEnvironmentConfig(options.environment);
if (!config || !config.profileToken) {
errorHandler("Environment not found");
return;
}
/**
* Retrieves a list of analysis from TagoIO that match the specified filter criteria.
* @param {Account} account - The TagoIO account object.
* @param {string | undefined} analysisFilterName - The name of the analysis to filter by.
* @param {string} filterMode - The mode to filter by (e.g. "release", "debug", etc.).
* @returns {Promise<AnalysisInfo[]>} - A promise that resolves to an array of AnalysisInfo objects.
*/
async function getAnalysisListFromTagoIO(account: Account, analysisFilterName: string | undefined, filterMode: string) {
const filterByRunON = (r: AnalysisInfo[]) => (filterMode ? r.filter((x) => x.run_on === filterMode) : r);

const account = new Account({ token: config.profileToken, region: "usa-1" });
const analysisFilterName = userInputName ? `*${userInputName}*` : undefined;

const analysisList = await account.analysis
return await account.analysis
.list({
amount: 100,
filter: { name: analysisFilterName },
fields: ["id", "name", "run_on"],
})
.then((r) => (options.filterMode ? r.filter((x) => x.run_on === options.filterMode) : r))
.then(filterByRunON)
.catch(errorHandler);
}

if (!analysisList) {
return;
}

infoMSG(`${analysisList.length} Analysis found`);
if (analysisList.length === 0) {
return;
}
/**
* Prompts the user to choose an analysis from a list and returns the selected analysis.
* @param {Account} account - The TagoIO account object.
* @param {AnalysisInfo[]} analysisList - The list of analysis to choose from.
* @returns {Promise<AnalysisInfo[]>} - The selected analysis object.
*/
async function chooseAnalysisToUpdateRunOnMode(account: Account, analysisList: AnalysisInfo[]): Promise<AnalysisInfo[]> {
const colorAnalysisName = (x: AnalysisInfo) => `${x.name} [${x.run_on === "tago" ? kleur.cyan(x.run_on) : kleur.yellow(x.run_on || "")}]`;

const renameAnalysis = (x: AnalysisInfo) => `${x.name} [${x.run_on === "tago" ? kleur.cyan(x.run_on) : kleur.yellow(x.run_on || "")}]`;
// Prompts the user to choose an analysis from a list.
const selectedAnalysis = await chooseFromList(
analysisList.sort((a) => (a.run_on === "external" ? -1 : 1)).map((x) => ({ value: x, title: renameAnalysis(x) })),
"Choose the analysis to update: "
analysisList.sort((a) => (a.run_on === "external" ? -1 : 1)).map((x) => ({ value: x, title: colorAnalysisName(x) })),
"Choose the analysis you want to update the run_on mode for:"
);

// Handles the case where the user cancels the selection.
if (!selectedAnalysis || selectedAnalysis.length === 0) {
errorHandler("Cancelled.");
return process.exit(0);
}

return selectedAnalysis;
}

/**
* Sets the run_on mode for one or more TagoIO analyses.
* @param userInputName - Optional name filter for the analyses to update.
* @param options - An object containing the environment, mode, and filterMode options.
* @param options.environment - The name of the environment to use.
* @param options.mode - The run_on mode to set for the selected analysis.
* @param options.filterMode - The filter mode to use when retrieving the analysis list.
*/
async function analysisSetMode(userInputName: string | void, options: { environment: string; mode: string; filterMode: string }) {
const config = getEnvironmentConfig(options.environment);
if (!config || !config.profileToken) {
errorHandler("Environment not found");
return;
}

const account = new Account({ token: config.profileToken, region: "usa-1" });
const analysisFilterName = userInputName ? `*${userInputName}*` : undefined;

// Get analysis list from TagoIO
const analysisList = await getAnalysisListFromTagoIO(account, analysisFilterName, options.filterMode);
if (!analysisList || analysisList.length === 0) {
errorHandler("No analysis found.");
return;
}
infoMSG(`${analysisList.length} analysis found.`);

// Query user for the analysis to update
const selectedAnalysis = await chooseAnalysisToUpdateRunOnMode(account, analysisList);

let mode: string = options.filterMode;
if (!mode) {
mode = await pickFromList([{ title: "tago" }, { title: "external" }], {
message: "You want to change run_on to?",
message: "Which run_on mode do you want to set for the selected analysis?",
initial: selectedAnalysis[0].run_on == "tago" ? "external" : "tago",
});
}

// Update analysis run_on mode
for (const analysis of selectedAnalysis) {
await account.analysis.edit(analysis.id, { run_on: mode as any });
}

successMSG(`${selectedAnalysis.length} Analysis run_on succesfully set to: ${mode}`);
successMSG(`${selectedAnalysis.length} Analysis run_on successfully set to: ${mode}`);
}

export { analysisSetMode };
Loading

0 comments on commit 12244ff

Please sign in to comment.