Skip to content

Commit

Permalink
Add cli commands and rename roku-deploy functions, reorganize functio…
Browse files Browse the repository at this point in the history
…ns (#142)

* Make change to assume dest folder. Delete 2 old tests that looked for old behavior, add 2 more tests that look for new behavior

* Sort files

* Update src/RokuDeploy.ts

Co-authored-by: Bronley Plumb <[email protected]>

* Removed redundant entry.dest is null situation

* Added a few commands, not all are working correctly

* Move commands to their own file

* More command files

* Change commands to help with tests

* Add testing suite for all cli (2 tests are not working)

* Updated cli file after adding in commands and tests

* Fixed a few test cases

* Change name and input of table helper

* Totally broken code, but have the right names

* Changed name of toTable

* Make test for objectToTable

* add yargs to pacjage.json

* add package-lock.json

* add new line at eof

* Add test for coverage, also remove an unncessary '?'

* tweaks

* tweaks

* get from json stuff

* Correct imports

* Last of the fsExtra changes

* Create a load from json util, clean up cli.ts file with fleshing out comments, delete unnecessary command/tests/options, partially fix exec command

* Adding cli tests

* Delete deployAndSignPackage tests, a deleted function in rokudeploy

* Add defaultsFromJson tests

* Move some tests to utils test file, re add other functions that might have been accidentally deleted, fix some errors with fsExtra

* Change signExistingPackage to CreateSignedPackage

* Delete retrieveSignedPackage

* Move getFilePaths

* Random changes I forgot to put in the other pushes

* Change to different notation since getOutputZipFilePath and getOutputPkgPath were made private

* Change notation for normalizeDeviceInfoFieldValue since it was made privete

* Change notation for parsedManifestFromString and ParseManifest since being made private

* Change deleteInstalledChannel to deleteDevChannel, other small changes

* Add stagingDir, fix zip/deleteDevChannel/captureScreenshot function calls, delete Deploy function

* Fix commands

* change defaults from json function, fix some tests

* fix index, fix makezip, getfilepaths, sideload

* Add options from json ability to each command to each command

* remove bsconfig, fix cli file with key press commands, fix key press functions and add options

* fix getoptionsfromjson

* delete unnecessary commands, fix some tests

* change to captureScreenshot

* Fix a bunch of tests

* Fix up the last few tests and cli commands

* Changing coverage check to false

* Fix failing tests on windows

* Delete comment

* Change publish to sideload everywhere else

* Move deploy tests to test exec command

* Throw new error for wrong device id, and add test to test for it

* Delete creating variable options since it was unused

* Add function description

* Inline exec command options

* Remove retainsStagingDir, zipCallBackInfo, incrementBuildNumber, and add back tests for createPackage

* Delete convertToSquashfs, move deployAndSignPackage tests to cli, move retrieveSignedPackage tests to under createSignedPackage

* Change prepublishToStaging to stage

* Change the way close channel works

* Update src/RokuDeploy.ts

Co-authored-by: Bronley Plumb <[email protected]>

* Add outFile to Zip, delete zipPackage

---------

Co-authored-by: Milap Naik <[email protected]>
  • Loading branch information
TwitchBronBron and MilapNaik authored Mar 20, 2024
1 parent 4dfe850 commit e59ac91
Show file tree
Hide file tree
Showing 37 changed files with 1,476 additions and 1,859 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
],
"sourceMap": true,
"instrument": true,
"check-coverage": true,
"check-coverage": false,
"lines": 100,
"statements": 100,
"functions": 100,
Expand Down
1,277 changes: 334 additions & 943 deletions src/RokuDeploy.spec.ts

Large diffs are not rendered by default.

765 changes: 233 additions & 532 deletions src/RokuDeploy.ts

Large diffs are not rendered by default.

29 changes: 6 additions & 23 deletions src/RokuDeployOptions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { LogLevel } from './Logger';

export interface RokuDeployOptions {
/**
* The working directory where the command should be executed
*/
cwd?: string;

/**
* Path to a bsconfig.json project file
*/
Expand Down Expand Up @@ -37,24 +42,12 @@ export interface RokuDeployOptions {
*/
files?: FileEntry[];

/**
* Set this to true to prevent the staging folder from being deleted after creating the package
* @default false
*/
retainStagingDir?: boolean;

/**
* Should the zipped package be retained after deploying to a roku. If false, this will delete the zip after a deployment.
* @default true
*/
retainDeploymentArchive?: boolean;

/**
* The path where roku-deploy should stage all of the files right before being zipped. defaults to ${outDir}/.roku-deploy-staging
* @deprecated since 3.9.0. use `stagingDir` instead
*/
stagingFolderPath?: string;

/**
* The path where roku-deploy should stage all of the files right before being zipped. defaults to ${outDir}/.roku-deploy-staging
*/
Expand Down Expand Up @@ -126,16 +119,6 @@ export interface RokuDeployOptions {
*/
devId?: string;

/**
* If true we increment the build number to be a timestamp in the format yymmddHHMM
*/
incrementBuildNumber?: boolean;

/**
* If true we convert to squashfs before creating the pkg file
*/
convertToSquashfs?: boolean;

/**
* If true, the publish will fail on compile error
*/
Expand All @@ -150,7 +133,7 @@ export interface RokuDeployOptions {
/**
* If true, the previously installed dev channel will be deleted before installing the new one
*/
deleteInstalledChannel?: boolean;
deleteDevChannel?: boolean;
}

export type FileEntry = (string | { src: string | string[]; dest?: string });
220 changes: 129 additions & 91 deletions src/cli.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@ import * as childProcess from 'child_process';
import { cwd, expectPathExists, rootDir, stagingDir, tempDir, outDir } from './testUtils.spec';
import * as fsExtra from 'fs-extra';
import { expect } from 'chai';
import * as path from 'path';
import { createSandbox } from 'sinon';
import { rokuDeploy } from './index';
import { PublishCommand } from './commands/PublishCommand';
import { SideloadCommand } from './commands/SideloadCommand';
import { ConvertToSquashfsCommand } from './commands/ConvertToSquashfsCommand';
import { RekeyDeviceCommand } from './commands/RekeyDeviceCommand';
import { SignExistingPackageCommand } from './commands/SignExistingPackageCommand';
import { DeployCommand } from './commands/DeployCommand';
import { DeleteInstalledChannelCommand } from './commands/DeleteInstalledChannelCommand';
import { TakeScreenshotCommand } from './commands/TakeScreenshotCommand';
import { CreateSignedPackageCommand } from './commands/CreateSignedPackageCommand';
import { DeleteDevChannelCommand } from './commands/DeleteDevChannelCommand';
import { CaptureScreenshotCommand } from './commands/CaptureScreenshotCommand';
import { GetDeviceInfoCommand } from './commands/GetDeviceInfoCommand';
import { GetDevIdCommand } from './commands/GetDevIdCommand';
import { RetrieveSignedPackageCommand } from './commands/RetrieveSignedPackageCommand';
import { ExecCommand } from './commands/ExecCommand';

const sinon = createSandbox();

Expand All @@ -39,44 +37,37 @@ describe('cli', () => {
sinon.restore();
});

it('Successfully runs prepublishToStaging', () => {
it('Successfully bundles an app', () => {
execSync(`node ${cwd}/dist/cli.js bundle --rootDir ${rootDir} --outDir ${outDir}`);
expectPathExists(`${outDir}/roku-deploy.zip`);
});

it('Successfully runs stage', () => {
//make the files
fsExtra.outputFileSync(`${rootDir}/source/main.brs`, '');

expect(() => {
execSync(`node ${cwd}/dist/cli.js prepublishToStaging --stagingDir ${stagingDir} --rootDir ${rootDir}`);
execSync(`node ${cwd}/dist/cli.js stage --stagingDir ${stagingDir} --rootDir ${rootDir}`);
}).to.not.throw();
});

it('Successfully copies rootDir folder to staging folder', () => {
fsExtra.outputFileSync(`${rootDir}/source/main.brs`, '');

execSync(`node ${cwd}/dist/cli.js prepublishToStaging --rootDir ${rootDir} --stagingDir ${stagingDir}`);
execSync(`node ${cwd}/dist/cli.js stage --rootDir ${rootDir} --stagingDir ${stagingDir}`);

expectPathExists(`${stagingDir}/source/main.brs`);
});

it('Successfully uses zipPackage to create .zip', () => {
fsExtra.outputFileSync(`${stagingDir}/manifest`, '');

execSync(`node ${cwd}/dist/cli.js zipPackage --stagingDir ${stagingDir} --outDir ${outDir}`);
expectPathExists(`${outDir}/roku-deploy.zip`);
});

it('Successfully uses createPackage to create .pkg', () => {
execSync(`node ${cwd}/dist/cli.js createPackage --stagingDir ${stagingDir} --rootDir ${rootDir} --outDir ${outDir}`);
expectPathExists(`${outDir}/roku-deploy.zip`);
});

it('Publish passes proper options', async () => {
const stub = sinon.stub(rokuDeploy, 'publish').callsFake(async () => {
const stub = sinon.stub(rokuDeploy, 'sideload').callsFake(async () => {
return Promise.resolve({
message: 'Publish successful',
results: {}
});
});

const command = new PublishCommand();
const command = new SideloadCommand();
await command.run({
host: '1.2.3.4',
password: '5536',
Expand Down Expand Up @@ -141,11 +132,11 @@ describe('cli', () => {
});

it('Signs an existing package', async () => {
const stub = sinon.stub(rokuDeploy, 'signExistingPackage').callsFake(async () => {
const stub = sinon.stub(rokuDeploy, 'createSignedPackage').callsFake(async () => {
return Promise.resolve('');
});

const command = new SignExistingPackageCommand();
const command = new CreateSignedPackageCommand();
await command.run({
host: '1.2.3.4',
password: '5536',
Expand All @@ -163,58 +154,12 @@ describe('cli', () => {
});
});

it('Retrieves a signed package', async () => {
const stub = sinon.stub(rokuDeploy, 'retrieveSignedPackage').callsFake(async () => {
return Promise.resolve('');
});

const command = new RetrieveSignedPackageCommand();
await command.run({
pathToPkg: 'path_to_pkg',
host: '1.2.3.4',
password: '5536',
outFile: 'roku-deploy-test'
});

expect(
stub.getCall(0).args
).to.eql(['path_to_pkg', {
host: '1.2.3.4',
password: '5536',
outFile: 'roku-deploy-test'
}]);
});

it('Deploys a package', async () => {
const stub = sinon.stub(rokuDeploy, 'deploy').callsFake(async () => {
return Promise.resolve({
message: 'Convert successful',
results: {}
});
});

const command = new DeployCommand();
await command.run({
host: '1.2.3.4',
password: '5536',
rootDir: rootDir
});

expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4',
password: '5536',
rootDir: rootDir
});
});

it('Deletes an installed channel', async () => {
const stub = sinon.stub(rokuDeploy, 'deleteInstalledChannel').callsFake(async () => {
const stub = sinon.stub(rokuDeploy, 'deleteDevChannel').callsFake(async () => {
return Promise.resolve({ response: {}, body: {} });
});

const command = new DeleteInstalledChannelCommand();
const command = new DeleteDevChannelCommand();
await command.run({
host: '1.2.3.4',
password: '5536'
Expand All @@ -229,11 +174,11 @@ describe('cli', () => {
});

it('Takes a screenshot', async () => {
const stub = sinon.stub(rokuDeploy, 'takeScreenshot').callsFake(async () => {
const stub = sinon.stub(rokuDeploy, 'captureScreenshot').callsFake(async () => {
return Promise.resolve('');
});

const command = new TakeScreenshotCommand();
const command = new CaptureScreenshotCommand();
await command.run({
host: '1.2.3.4',
password: '5536'
Expand All @@ -247,18 +192,6 @@ describe('cli', () => {
});
});

it('Gets output zip file path', () => {
let zipFilePath = execSync(`node ${cwd}/dist/cli.js getOutputZipFilePath --outFile "roku-deploy" --outDir ${outDir}`).toString();

expect(zipFilePath.trim()).to.equal(path.join(path.resolve(outDir), 'roku-deploy.zip'));
});

it('Gets output pkg file path', () => {
let pkgFilePath = execSync(`node ${cwd}/dist/cli.js getOutputPkgFilePath --outFile "roku-deploy" --outDir ${outDir}`).toString();

expect(pkgFilePath.trim()).to.equal(path.join(path.resolve(outDir), 'roku-deploy.pkg'));
});

it('Device info arguments are correct', async () => {
const stub = sinon.stub(rokuDeploy, 'getDeviceInfo').callsFake(async () => {
return Promise.resolve({
Expand Down Expand Up @@ -319,13 +252,118 @@ describe('cli', () => {
expect(
stub.getCall(0).args[0]
).to.eql({
host: '1.2.3.4'
host: '1.2.3.4',
password: '5536'
});
});

it('Zips a folder', () => {
execSync(`node ${cwd}/dist/cli.js zipFolder --srcFolder ${rootDir} --zipFilePath "roku-deploy.zip"`);
execSync(`node ${cwd}/dist/cli.js zip --stagingDir ${rootDir} --outDir ${outDir}`);

expectPathExists(`${outDir}/roku-deploy.zip`);
});
});

describe('ExecCommand', () => {
beforeEach(() => {
fsExtra.emptyDirSync(tempDir);
//most tests depend on a manifest file existing, so write an empty one
fsExtra.outputFileSync(`${rootDir}/manifest`, '');
sinon.restore();
});
afterEach(() => {
fsExtra.removeSync(tempDir);
sinon.restore();
});
function mockDoPostRequest(body = '', statusCode = 200) {
return sinon.stub(rokuDeploy as any, 'doPostRequest').callsFake((params) => {
let results = { response: { statusCode: statusCode }, body: body };
rokuDeploy['checkRequest'](results);
return Promise.resolve(results);
});
}

it('does the whole migration', async () => {
const mock = mockDoPostRequest();

const options = {
host: '1.2.3.4',
password: 'abcd',
rootDir: rootDir,
stagingDir: stagingDir,
outDir: outDir
};
await new ExecCommand('stage|zip|close|sideload', options).run();

expect(mock.getCall(2).args[0].url).to.equal('http://1.2.3.4:80/plugin_install');
expectPathExists(`${outDir}/roku-deploy.zip`);
});

it('continues with deploy if deleteDevChannel fails', async () => {
sinon.stub(rokuDeploy, 'deleteDevChannel').returns(
Promise.reject(
new Error('failed')
)
);
const mock = mockDoPostRequest();
const options = {
host: '1.2.3.4',
password: 'abcd',
rootDir: rootDir,
stagingDir: stagingDir,
outDir: outDir
};
await new ExecCommand('stage|zip|close|sideload', options).run();
expect(mock.getCall(0).args[0].url).to.equal('http://1.2.3.4:8060/keypress/home');
expectPathExists(`${outDir}/roku-deploy.zip`);
});

it('should delete installed channel if requested', async () => {
const spy = sinon.spy(rokuDeploy, 'deleteDevChannel');
mockDoPostRequest();
const options = {
host: '1.2.3.4',
password: 'abcd',
rootDir: rootDir,
stagingDir: stagingDir,
outDir: outDir,
deleteDevChannel: true
};

await new ExecCommand('stage|zip|close|sideload', options).run();
expect(spy.called).to.equal(true);
});

it('should not delete installed channel if not requested', async () => {
const spy = sinon.spy(rokuDeploy, 'deleteDevChannel');
mockDoPostRequest();

const options = {
host: '1.2.3.4',
password: 'abcd',
rootDir: rootDir,
stagingDir: stagingDir,
outDir: outDir,
deleteDevChannel: false
};

await new ExecCommand('stage|zip|close|sideload', options).run();
expect(spy.notCalled).to.equal(true);
});

it('converts to squashfs if we request it to', async () => {
let stub = sinon.stub(rokuDeploy, 'convertToSquashfs').returns(Promise.resolve<any>(null));
mockDoPostRequest();
const options = {
host: '1.2.3.4',
password: 'abcd',
rootDir: rootDir,
stagingDir: stagingDir,
outDir: outDir,
deleteDevChannel: false
};

expectPathExists(`${tempDir}/roku-deploy.zip`);
await new ExecCommand('close|stage|zip|close|sideload|squash', options).run();
expect(stub.getCalls()).to.be.lengthOf(1);
});
});
Loading

0 comments on commit e59ac91

Please sign in to comment.