Skip to content

Commit

Permalink
Run command arguments elaboration
Browse files Browse the repository at this point in the history
  • Loading branch information
fantonangeli committed Nov 13, 2021
1 parent a6f5fd8 commit dc15c1a
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.clasp.json
.multi-clasp.json
.tags
.DS_Store
node_modules
Expand Down
33 changes: 27 additions & 6 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as util from 'util';
import * as child_process from 'child_process';
const exec = util.promisify(child_process.exec);
import { Config } from './config';
import {OptionValues} from 'commander';


/**
Expand Down Expand Up @@ -43,23 +44,43 @@ export function readMultiClaspConfig(): SingleClasp[] {
return JSON.parse(fs.readFileSync(Config.MULTICLASP_FILENAME, Config.UTF_8 as BufferEncoding).toString());
}

/**
* Get the Options for the clasp command.
*
* @param args array of arguments
* @returns the string with the options, "" otherwise
*/
export function getOptions (args:string[]=process.argv):string {
if (!args) {
return "";
}
return args.slice(3).join(' ');
}

/**
* commander action to run clasp.
*
* @returns
*/
export async function genericAction(): Promise<void> {
let retVal=true;
export async function foreachClasp(fn:(claspConfig:SingleClasp)=>Promise<void>):Promise<void> {
const clasps = readMultiClaspConfig();

for (let i = 0, len = clasps.length; i < len; i++) {
retVal = await runClasp(clasps[i], process.argv[2], process.argv.slice(3).join(' '));
if (!retVal) {
return;
}
await fn(clasps[i]);
}

fs.unlink(Config.CLASP_FILENAME, (err) => {
if (err) throw err;
});
}

/**
* commander action to run clasp.
*
* @returns
*/
export async function genericAction(): Promise<void> {
foreachClasp(async (claspConfig)=>{
await runClasp(claspConfig, process.argv[2], getOptions());
});
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Command } from 'commander';
import { Config } from './config';
import { genericAction, readMultiClaspConfig, runClasp } from './common';
import {version} from '../package.json';
import run from './run';

const program = new Command();

Expand Down Expand Up @@ -50,7 +51,7 @@ program
.description('Run a function in your Apps Scripts project')
.option('--nondev', 'Run script function in non-devMode')
.option('-p, --params [StringArray]', 'Add parameters required for the function as a JSON String Array')
.action(genericAction);
.action(run);

program
.command('version [description]')
Expand Down
47 changes: 47 additions & 0 deletions src/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {foreachClasp, runClasp} from "./common";
import {parseJsonOrDie} from "./utils";

interface CommandOption {
readonly nondev: boolean;
readonly params: string;
}

/**
* Get Clasp Arguments.
*
* @param functionName {string} The function name within the Apps Script project.
* @param options.nondev {boolean} If we want to run the last deployed version vs the latest code.
* @param options.params {string} JSON string of parameters to be input to function.
* @returns {string} the command arguments
*/
export function getRunClaspArgs(functionName="", options: CommandOption): string{
let claspArgs = functionName || "";
const {params: jsonString = '[]'} = options;
const parameters = parseJsonOrDie<string[]>(jsonString);

if (!options) {
return claspArgs;
}

claspArgs += options.nondev?" --nondev":"";

claspArgs += " --params '"+JSON.stringify(parameters)+"'";

return claspArgs;
}

/**
* Executes an Apps Script function. Requires clasp login --creds.
* @param functionName {string} The function name within the Apps Script project.
* @param options.nondev {boolean} If we want to run the last deployed version vs the latest code.
* @param options.params {string} JSON string of parameters to be input to function.
* @see https://developers.google.com/apps-script/api/how-tos/execute
* @requires `clasp login --creds` to be run beforehand.
*/
export default async (functionName: string, options: CommandOption): Promise<void> => {
const claspArgs = getRunClaspArgs(functionName, options);

foreachClasp(async (claspConfig)=>{
await runClasp(claspConfig, process.argv[2], claspArgs);
});
}
11 changes: 11 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Parses input string into a valid JSON object or throws a `ClaspError` error.
* @param value JSON string.
*/
export const parseJsonOrDie = <T>(value: string): T => {
try {
return JSON.parse(value) as T;
} catch {
throw "Invalid json";
}
};
15 changes: 14 additions & 1 deletion test/test.ts → test/common.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as fs from "fs";
import { runClasp } from '../src/common';
import { getOptions, runClasp } from '../src/common';

jest.mock('util', () => ({
promisify: jest.fn(() => {
Expand All @@ -24,4 +24,17 @@ describe('common.js tests', () => {
expect(fs.writeFile).toHaveBeenCalledTimes(1);
});
});

describe('getOptions', () => {
test('wrong inputs', () => {
expect(getOptions([])).toBe("");
expect(getOptions(undefined)).toBe("");
})
test('good inputs', () => {
expect(getOptions(["node", "multi-clasp", "push"])).toBe("");
expect(getOptions(["node", "multi-clasp", "push", "-f"])).toBe("-f");
expect(getOptions(["node", "multi-clasp", "push", "-f", "-g", "what"])).toBe("-f -g what");
expect(getOptions(["node", "multi-clasp", "run", "-p", '\'["what"]\''])).toBe("-p '[\"what\"]'");
})
});
});
13 changes: 13 additions & 0 deletions test/run.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {getRunClaspArgs} from "../src/run";


describe('run.ts tests', ()=>{
test('wrong inputs', () => {
expect(()=>(getRunClaspArgs("", {nondev:false, params:''}))).toThrow("Invalid json");
});
test('good inputs', () => {
expect(getRunClaspArgs("testFunc", {nondev:false, params:'[]'})).toBe("testFunc --params '[]'");
expect(getRunClaspArgs("testFunc", {nondev:false, params:'["dino"]'})).toBe("testFunc --params '[\"dino\"]'");
expect(getRunClaspArgs("testFunc", {nondev:true, params:'["dino", "pepe"]'})).toBe("testFunc --nondev --params '[\"dino\",\"pepe\"]'");
});
})

0 comments on commit dc15c1a

Please sign in to comment.