Skip to content

Commit

Permalink
Merge pull request #90 from AElfProject/feature/csv
Browse files Browse the repository at this point in the history
feat: csv
  • Loading branch information
hzz780 authored Aug 23, 2024
2 parents 1d91276 + c6e1d8f commit 52ca774
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 36 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
test:
Expand Down
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,17 @@
</a>
</p>

| Branch | Tests | Coverage |
|--------------|-----------------|----------------|
| Branch | Tests | Coverage |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `master` | ![Tests](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/AElfProject/aelf-command/feature/badge-json/master-test-results.json) | ![Coverage](https://AElfProject.github.io/aelf-command/badges.svg) |




## Descriptions

_A CLI tools built for AElf_

## Features

- Get or Set common configs, `endpoint`, `account`, `datadir`, `password`.
- Get or Set common configs, `endpoint`, `account`, `datadir`, `password`, `csv`.
- For new users who are not familiar with the CLI parameters, any missing parameters will be asked in a prompting way.
- Create a new `account`.
- Load an account from a given `private key` or `mnemonic`.
Expand Down Expand Up @@ -157,6 +154,7 @@ Options:
-a, --account <account> The address of AElf wallet
-p, --password <password> The password of encrypted keyStore
-d, --datadir <directory> The directory that contains the AElf related files. Defaults to {home}/.local/share/aelf
-c, --csv <csv> The location of the CSV file containing the parameters.
-h, --help output usage information

Commands:
Expand Down Expand Up @@ -218,6 +216,7 @@ aelf-command console
- `endpoint`: The endpoint for the RPC service.
- `account`: The account to be used to interact with the blockchain `endpoint`.
- `password`: The password for unlocking the given `account`.
- `csv>`: The location of the CSV file containing the parameters.
You can specified options above in several ways, and the priority is in the order of low to high.
Expand Down
4 changes: 2 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default {
coveragePathIgnorePatterns: ['/node_modules/', '/src/utils/constants.js', '/src/command/index.js'],

// A list of reporter names that Jest uses when writing coverage reports
coverageReporters: ['text', 'json-summary'],
coverageReporters: ['text', 'json-summary', 'html'],

// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: null,
Expand Down Expand Up @@ -146,7 +146,7 @@ export default {

// The glob patterns Jest uses to detect test files
testMatch: [
// '**/test/utils/Logger.test.js'
// '**/test/utils/utils.test.js'
'**/test/command/dappServer/socket-sign.test.js',
'**/test/**/?(*.)+(spec|test).[jt]s?(x)'
// "**/?(*.)+(spec|test).[tj]s?(x)"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aelf-command",
"version": "0.1.48",
"version": "0.1.49-beta.0",
"description": "A CLI tools for AElf",
"main": "src/index.js",
"type": "module",
Expand Down Expand Up @@ -56,6 +56,7 @@
"check-node-version": "^4.2.1",
"columnify": "^1.6.0",
"commander": "^12.1.0",
"csv-parser": "^3.0.0",
"elliptic": "^6.5.5",
"inquirer": "^9.2.22",
"inquirer-date-prompt": "^3.0.0",
Expand Down
4 changes: 2 additions & 2 deletions src/command/baseSubCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import inquirer from 'inquirer';
import ora from 'ora';
import { logger } from '../utils/myLogger.js';
import { camelCase } from '../utils/utils.js';
import { globalOptionsPrompts, strictGlobalOptionValidatorDesc } from '../utils/constants.js';
import { commonGlobalOptionValidatorDesc, globalOptionsPrompts, strictGlobalOptionValidatorDesc } from '../utils/constants.js';

// Schema.warning = () => {}; // TypeError: Cannot add property warning, object is not extensible

Expand Down Expand Up @@ -123,7 +123,7 @@ class BaseSubCommand {
*/
static getUniConfig(commander) {
const result = {};
['password', 'endpoint', 'account', 'datadir'].forEach(v => {
Object.keys(commonGlobalOptionValidatorDesc).forEach(v => {
const options = commander.opts();
if (options[v]) {
result[v] = options[v];
Expand Down
53 changes: 40 additions & 13 deletions src/command/call.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import AElf from 'aelf-sdk';
import inquirer from 'inquirer';
import chalk from 'chalk';
import { createReadStream } from 'fs';
import csv from 'csv-parser';
import BaseSubCommand from './baseSubCommand.js';
import { callCommandUsages, callCommandParameters } from '../utils/constants.js';
import {
Expand All @@ -9,7 +11,8 @@ import {
getMethod,
promptTolerateSeveralTimes,
getParams,
parseJSON
parseJSON,
parseCSV
} from '../utils/utils.js';
import { getWallet } from '../utils/wallet.js';
import { logger } from '../utils/myLogger.js';
Expand Down Expand Up @@ -64,6 +67,19 @@ class CallCommand extends BaseSubCommand {
return contractAddress;
}

/**
* Calls a method with specified parameters.
* @param {any} method The method to call.
* @param {any} params The parameters for the method call.
* @returns {Promise<any>} A promise that resolves with the result of the method call.
*/
async showRes(method, params) {
const result = await this.callMethod(method, params);
// @ts-ignore
logger.info(`\nResult:\n${JSON.stringify(result, null, 2)}`);
this.oraInstance.succeed('Succeed!');
}

/**
* Runs the command.
* @param {Command} commander The Commander instance.
Expand All @@ -75,7 +91,7 @@ class CallCommand extends BaseSubCommand {
// @ts-ignore
const { options, subOptions } = await super.run(commander, ...args);
const subOptionsLength = Object.keys(subOptions).length;
const { endpoint, datadir, account, password } = options;
const { endpoint, datadir, account, password, csv } = options;
const aelf = new AElf(new AElf.providers.HttpProvider(endpoint));
try {
let { contractAddress, method, params } = subOptions;
Expand Down Expand Up @@ -109,13 +125,16 @@ class CallCommand extends BaseSubCommand {
break;
case 'params':
contractAddress = await getContractInstance(contractAddress, aelf, wallet, this.oraInstance);

method = getMethod(method, contractAddress);

params = await getParams(method);
params = typeof params === 'string' ? params : BaseSubCommand.normalizeConfig(params);
if (Object.keys(params || {}).length > 0) {
console.log(chalk.hex('#3753d3')(`The params you entered is:\n${JSON.stringify(params, null, 2)}`));
if (csv) {
const csvParams = await parseCSV(csv);
params = csvParams;
} else {
params = await getParams(method);
params = typeof params === 'string' ? params : BaseSubCommand.normalizeConfig(params);
if (Object.keys(params || {}).length > 0) {
console.log(chalk.hex('#3753d3')(`The params you entered is:\n${JSON.stringify(params, null, 2)}`));

Check warning on line 136 in src/command/call.js

View workflow job for this annotation

GitHub Actions / Setup

Unexpected console statement
}
}
break;
default:
Expand All @@ -124,15 +143,23 @@ class CallCommand extends BaseSubCommand {
}
}
contractAddress = await getContractInstance(contractAddress, aelf, wallet, this.oraInstance);
params = parseJSON(params);
if (Array.isArray(params)) {
params.forEach(param => parseJSON(param));
} else {
params = parseJSON(params);
}

method = getMethod(method, contractAddress);
if (method.inputTypeInfo && (Object.keys(method.inputTypeInfo.fields).length === 0 || !method.inputTypeInfo.fields)) {
params = '';
}
const result = await this.callMethod(method, params);
// @ts-ignore
logger.info(`\nResult:\n${JSON.stringify(result, null, 2)}`);
this.oraInstance.succeed('Succeed!');
if (Array.isArray(params)) {
for (const param of params) {
await this.showRes(method, param);
}
} else {
await this.showRes(method, params);
}
} catch (e) {
this.oraInstance.fail('Failed!');
// @ts-ignore
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ function init(options) {
commander.option('-e, --endpoint <URI>', 'The URI of an AElf node. Eg: http://127.0.0.1:8000');
commander.option('-a, --account <account>', 'The address of AElf wallet');
commander.option('-p, --password <password>', 'The password of encrypted keyStore');

commander.option(
'-d, --datadir <directory>',
`The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf`
);
commander.option('-c, --csv <csv>', 'The location of the CSV file containing the parameters.');
const rc = new RC();
Object.values(commands).forEach(Value => {
const command = new Value(rc);
Expand Down
9 changes: 7 additions & 2 deletions src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,11 @@ const commonGlobalOptionValidatorDesc = {
type: 'string',
required: false,
message: 'set a valid account address in global config file or passed by -a <address>'
},
csv: {
type: 'string',
required: false,
message: 'set params in csv file by -c <csv>'
}
};

Expand All @@ -374,8 +379,8 @@ const strictGlobalOptionValidatorDesc = /**@type {CommonGlobalOptionValidatorDes
// @ts-ignore
Object.entries(commonGlobalOptionValidatorDesc).forEach((/** @type {[CommonGlobalOptionKey, any]} */ [key, value]) => {
strictGlobalOptionValidatorDesc[key] = {
...value,
required: true
...value
// required: true
};
});

Expand Down
22 changes: 21 additions & 1 deletion src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import _camelCase from 'camelcase';
import inquirer from 'inquirer';
import { plainLogger } from './myLogger.js';
import protobuf from '@aelfqueen/protobufjs';
import { createReadStream } from 'fs';
import csv from 'csv-parser';
const { load } = protobuf;

/**
Expand Down Expand Up @@ -462,6 +464,23 @@ async function deserializeLogs(aelf, logs = []) {
return results;
}

const parseCSV = async address => {
let results = [];
const stream = createReadStream(address).pipe(csv());
for await (const data of stream) {
const cleanData = {};
for (const key in data) {
const cleanKey = key.replace(/\n/g, '').trim();
const cleanValue = typeof data[key] === 'string' ? data[key].replace(/\n/g, '').trim() : data[key];
if (cleanValue !== '') {
cleanData[cleanKey] = cleanValue;
}
}
Object.keys(cleanData).length && results.push(cleanData);
}
return results;
};

export {
promisify,
camelCase,
Expand All @@ -474,5 +493,6 @@ export {
parseJSON,
randomId,
getParams,
deserializeLogs
deserializeLogs,
parseCSV
};
22 changes: 21 additions & 1 deletion test/command/call.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { callCommandUsages, callCommandParameters } from '../../src/utils/consta
import { getContractInstance } from '../../src/utils/utils.js';
import { userHomeDir } from '../../src/utils/userHomeDir.js';
import { logger } from '../../src/utils/myLogger.js';
import { endpoint as endPoint, account, password, dataDir } from '../constants.js';
import { endpoint as endPoint, account, password, dataDir, csvDir } from '../constants.js';

const sampleRc = { getConfigs: jest.fn() };
jest.mock('../../src/utils/myLogger');
Expand Down Expand Up @@ -102,6 +102,26 @@ describe('CallCommand', () => {
expect(logger.info).toHaveBeenCalled();
});

test('should run with csv', async () => {
inquirer.prompt = questions =>
Promise.resolve({
symbol: 'ELF',
owner: 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'
});
const commander = new Command();
commander.option('-e, --endpoint <URI>', 'The URI of an AElf node. Eg: http://127.0.0.1:8000');
commander.option('-a, --account <account>', 'The address of AElf wallet');
commander.option('-p, --password <password>', 'The password of encrypted keyStore');
commander.option(
'-d, --datadir <directory>',
`The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf`
);
commander.option('-c, --csv <csv>', 'The location of the CSV file containing the parameters.');
commander.parse([process.argv[0], '', 'call', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir, '-c', csvDir]);
await callCommand.run(commander, 'AElf.ContractNames.Token', 'GetBalance');
expect(logger.info).toHaveBeenCalled();
});

test('should run with invalid parameters', async () => {
inquirer.prompt = backup;
callCommand = new CallCommand(sampleRc, 'call', 'Call a read-only method on a contract.', [
Expand Down
2 changes: 0 additions & 2 deletions test/command/proposal.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
/* eslint-disable max-len */
import { Command } from 'commander';
import path from 'path';
import inquirer from 'inquirer';
import AElf from 'aelf-sdk';
import chalk from 'chalk';
import moment from 'moment';
import ProposalCommand from '../../src/command/proposal.js';
import { userHomeDir } from '../../src/utils/userHomeDir.js';
Expand Down
1 change: 1 addition & 0 deletions test/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export const endpoint = 'https://tdvw-test-node.aelf.io/';
export const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk';
export const password = '1234*Qwer';
export const dataDir = path.resolve(__dirname, './dataDir/aelf');
export const csvDir = path.resolve(__dirname, './test.csv');
3 changes: 3 additions & 0 deletions test/test.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
symbol,"owner
"
ELF,GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk
12 changes: 10 additions & 2 deletions test/utils/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import {
parseJSON,
randomId,
getParams,
deserializeLogs
deserializeLogs,
parseCSV
} from '../../src/utils/utils';
import { plainLogger } from '../../src/utils/myLogger';
import { endpoint, account, password, dataDir } from '../constants.js';
import { endpoint, account, password, dataDir, csvDir } from '../constants.js';

jest.mock('inquirer');

Expand Down Expand Up @@ -391,4 +392,11 @@ describe('utils', () => {
expect(result).toEqual(null);
});
});

describe('parseCSV', () => {
test('test parse csv file', async () => {
const results = await parseCSV(csvDir);
expect(results).toEqual([{ owner: 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk', symbol: 'ELF' }]);
});
});
});
6 changes: 6 additions & 0 deletions types/utils/constants.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,17 @@ export interface AccountValidatorDesc {
required: boolean;
message: string;
}
export interface CSVValidatorDesc {
type: string;
required: boolean;
message: string;
}
export interface CommonGlobalOptionValidatorDesc {
password: PasswordValidatorDesc;
endpoint: EndpointValidatorDesc;
datadir: DatadirValidatorDesc;
account: AccountValidatorDesc;
csv: CSVValidatorDesc;
}
export const commonGlobalOptionValidatorDesc: CommonGlobalOptionValidatorDesc;

Expand Down
7 changes: 7 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3085,6 +3085,13 @@ crypto-random-string@^4.0.0:
dependencies:
type-fest "^1.0.1"

csv-parser@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/csv-parser/-/csv-parser-3.0.0.tgz#b88a6256d79e090a97a1b56451f9327b01d710e7"
integrity sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ==
dependencies:
minimist "^1.2.0"

[email protected], cz-conventional-changelog@^3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz#9246947c90404149b3fe2cf7ee91acad3b7d22d2"
Expand Down

0 comments on commit 52ca774

Please sign in to comment.