From 2c98b75c9d1d261fce4214b96eeabcd31889c5b1 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Wed, 8 Nov 2023 15:32:13 +0100 Subject: [PATCH 01/30] Rough draft of adding individual interfaces --- src/RokuDeploy.spec.ts | 166 ++++++++++++++++++++--------------------- src/RokuDeploy.ts | 164 +++++++++++++++++++++++++++++----------- src/device.spec.ts | 2 +- 3 files changed, 203 insertions(+), 129 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 74415e2..c3823b2 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -55,13 +55,13 @@ describe('index', () => { describe('getOutputPkgFilePath', () => { it('should return correct path if given basename', () => { options.outFile = 'roku-deploy'; - let outputPath = rokuDeploy.getOutputPkgFilePath(options); + let outputPath = rokuDeploy.getOutputPkgFilePath(options as any); expect(outputPath).to.equal(path.join(path.resolve(options.outDir), options.outFile + '.pkg')); }); it('should return correct path if given outFile option ending in .zip', () => { options.outFile = 'roku-deploy.zip'; - let outputPath = rokuDeploy.getOutputPkgFilePath(options); + let outputPath = rokuDeploy.getOutputPkgFilePath(options as any); expect(outputPath).to.equal(path.join(path.resolve(options.outDir), 'roku-deploy.pkg')); }); }); @@ -69,13 +69,13 @@ describe('index', () => { describe('getOutputZipFilePath', () => { it('should return correct path if given basename', () => { options.outFile = 'roku-deploy'; - let outputPath = rokuDeploy.getOutputZipFilePath(options); + let outputPath = rokuDeploy.getOutputZipFilePath(options as any); expect(outputPath).to.equal(path.join(path.resolve(options.outDir), options.outFile + '.zip')); }); it('should return correct path if given outFile option ending in .zip', () => { options.outFile = 'roku-deploy.zip'; - let outputPath = rokuDeploy.getOutputZipFilePath(options); + let outputPath = rokuDeploy.getOutputZipFilePath(options as any); expect(outputPath).to.equal(path.join(path.resolve(options.outDir), 'roku-deploy.zip')); }); }); @@ -550,7 +550,7 @@ describe('index', () => { try { options.stagingDir = s`${tempDir}/path/to/nowhere`; fsExtra.ensureDirSync(options.stagingDir); - await rokuDeploy.zipPackage(options); + await rokuDeploy.zipPackage(options as any); } catch (e) { err = (e as Error); } @@ -561,7 +561,7 @@ describe('index', () => { let err; try { options.stagingDir = s`${tempDir}/path/to/nowhere`; - await rokuDeploy.zipPackage(options); + await rokuDeploy.zipPackage(options as any); } catch (e) { err = (e as Error); } @@ -580,14 +580,14 @@ describe('index', () => { ], stagingDir: '.tmp/dist' }; - await rokuDeploy.createPackage(opts); - expectPathExists(rokuDeploy.getOutputZipFilePath(opts)); + await rokuDeploy.createPackage(opts as any); + expectPathExists(rokuDeploy.getOutputZipFilePath(opts as any)); }); it('should throw error when no files were found to copy', async () => { await assertThrowsAsync(async () => { options.files = []; - await rokuDeploy.createPackage(options); + await rokuDeploy.createPackage(options as any); }); }); @@ -597,15 +597,15 @@ describe('index', () => { files: [ 'manifest' ] - }); - expectPathExists(rokuDeploy.getOutputZipFilePath(options)); + } as any); + expectPathExists(rokuDeploy.getOutputZipFilePath(options as any)); }); it('should only include the specified files', async () => { const files = ['manifest']; options.files = files; - await rokuDeploy.createPackage(options); - const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath(options)); + await rokuDeploy.createPackage(options as any); + const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath(options as any)); const zip = await JSZip.loadAsync(data); for (const file of files) { @@ -627,9 +627,9 @@ describe('index', () => { ...options, //target a subset of the files to make the test faster files: filePaths - }); + } as any); - const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath(options)); + const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath(options as any)); const zip = await JSZip.loadAsync(data); for (const file of filePaths) { @@ -646,10 +646,10 @@ describe('index', () => { files: [ 'manifest' ] - }); + } as any); expectPathExists(stagingDirValue); options.retainStagingDir = true; - await rokuDeploy.zipPackage(options); + await rokuDeploy.zipPackage(options as any); expectPathExists(stagingDirValue); }); @@ -661,7 +661,7 @@ describe('index', () => { expect(info.manifestData.major_version).to.equal('1'); }); - await rokuDeploy.createPackage(options, spy); + await rokuDeploy.createPackage(options as any, spy); if (spy.notCalled) { assert.fail('Callback not called'); @@ -674,7 +674,7 @@ describe('index', () => { await rokuDeploy.createPackage({ ...options, files: ['manifest'] - }, (info) => { + } as any, (info) => { return Promise.resolve().then(() => { count++; }).then(() => { @@ -693,7 +693,7 @@ describe('index', () => { await rokuDeploy.createPackage({ ...options, files: ['manifest'] - }, (info) => { + } as any, (info) => { beforeZipInfo = info; }); expect(beforeZipInfo.manifestData.build_version).to.not.equal('0'); @@ -707,7 +707,7 @@ describe('index', () => { files: [ 'manifest' ] - }, (info) => { + } as any, (info) => { expect(info.manifestData.build_version).to.equal('0'); }); }); @@ -722,11 +722,11 @@ describe('index', () => { describe('generateBaseRequestOptions', () => { it('uses default port', () => { - expect(rokuDeploy['generateBaseRequestOptions']('a_b_c', { host: '1.2.3.4' }).url).to.equal('http://1.2.3.4:80/a_b_c'); + expect(rokuDeploy['generateBaseRequestOptions']('a_b_c', { host: '1.2.3.4' } as any).url).to.equal('http://1.2.3.4:80/a_b_c'); }); it('uses overridden port', () => { - expect(rokuDeploy['generateBaseRequestOptions']('a_b_c', { host: '1.2.3.4', packagePort: 999 }).url).to.equal('http://1.2.3.4:999/a_b_c'); + expect(rokuDeploy['generateBaseRequestOptions']('a_b_c', { host: '1.2.3.4', packagePort: 999 } as any).url).to.equal('http://1.2.3.4:999/a_b_c'); }); }); @@ -811,7 +811,7 @@ describe('index', () => { //the file should exist expect(fsExtra.pathExistsSync(zipPath)).to.be.true; - await rokuDeploy.publish(options); + await rokuDeploy.publish(options as any); //the file should still exist expect(fsExtra.pathExistsSync(zipPath)).to.be.true; }); @@ -823,7 +823,7 @@ describe('index', () => { //the file should exist expect(fsExtra.pathExistsSync(zipPath)).to.be.true; - await rokuDeploy.publish({ ...options, retainDeploymentArchive: false }); + await rokuDeploy.publish({ ...options, retainDeploymentArchive: false } as any); //the file should not exist expect(fsExtra.pathExistsSync(zipPath)).to.be.false; //the out folder should also be deleted since it's empty @@ -848,7 +848,7 @@ describe('index', () => { //the file should exist expect(fsExtra.pathExistsSync(zipPath)).to.be.true; - await rokuDeploy.publish({ ...options, retainDeploymentArchive: false }); + await rokuDeploy.publish({ ...options, retainDeploymentArchive: false } as any); //the file should not exist expect(fsExtra.pathExistsSync(zipPath)).to.be.false; //the out folder should also be deleted since it's empty @@ -857,13 +857,13 @@ describe('index', () => { it('fails when the zip file is missing', async () => { options.outFile = 'fileThatDoesNotExist.zip'; await expectThrowsAsync(async () => { - await rokuDeploy.publish(options); - }, `Cannot publish because file does not exist at '${rokuDeploy.getOutputZipFilePath(options)}'`); + await rokuDeploy.publish(options as any); + }, `Cannot publish because file does not exist at '${rokuDeploy.getOutputZipFilePath(options as any)}'`); }); it('fails when no host is provided', () => { expectPathNotExists('rokudeploy.json'); - return rokuDeploy.publish({ host: undefined }).then(() => { + return rokuDeploy.publish({ host: undefined } as any).then(() => { assert.fail('Should not have succeeded'); }, () => { expect(true).to.be.true; @@ -884,7 +884,7 @@ describe('index', () => { }); try { - await rokuDeploy.publish(options); + await rokuDeploy.publish(options as any); } catch (e) { assert.ok('Exception was thrown as expected'); return; @@ -899,7 +899,7 @@ describe('index', () => { Shell.create('Roku.Message').trigger('Set message type', 'error').trigger('Set message content', 'Install Failure: Compilation Failed').trigger('Render', node); `); - return rokuDeploy.publish(options).then(() => { + return rokuDeploy.publish(options as any).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { expect(err).to.be.instanceOf(errors.CompileError); @@ -913,7 +913,7 @@ describe('index', () => { Shell.create('Roku.Message').trigger('Set message type', 'error').trigger('Set message content', 'Install Failure: Compilation Failed').trigger('Render', node); `); - return rokuDeploy.publish(options).then(() => { + return rokuDeploy.publish(options as any).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { expect(err).to.be.instanceOf(errors.CompileError); @@ -925,7 +925,7 @@ describe('index', () => { let body = 'Install Failure: Compilation Failed.'; mockDoPostRequest(body); - return rokuDeploy.publish(options).then(() => { + return rokuDeploy.publish(options as any).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { expect(err.message).to.equal('Compile error'); @@ -937,7 +937,7 @@ describe('index', () => { options.failOnCompileError = true; mockDoPostRequest('', 401); - return rokuDeploy.publish(options).then(() => { + return rokuDeploy.publish(options as any).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { expect(err.message).to.equal('Unauthorized. Please verify username and password for target Roku.'); @@ -949,7 +949,7 @@ describe('index', () => { options.failOnCompileError = true; mockDoPostRequest(); - return rokuDeploy.publish(options).then((result) => { + return rokuDeploy.publish(options as any).then((result) => { expect(result.message).to.equal('Successful deploy'); }, () => { assert.fail('Should not have rejected the promise'); @@ -961,7 +961,7 @@ describe('index', () => { options.remoteDebug = true; const stub = mockDoPostRequest(); - return rokuDeploy.publish(options).then((result) => { + return rokuDeploy.publish(options as any).then((result) => { expect(result.message).to.equal('Successful deploy'); expect(stub.getCall(0).args[0].formData.remotedebug).to.eql('1'); }, () => { @@ -975,7 +975,7 @@ describe('index', () => { options.remoteDebugConnectEarly = true; const stub = mockDoPostRequest(); - return rokuDeploy.publish(options).then((result) => { + return rokuDeploy.publish(options as any).then((result) => { expect(result.message).to.equal('Successful deploy'); expect(stub.getCall(0).args[0].formData.remotedebug_connect_early).to.eql('1'); }, () => { @@ -989,7 +989,7 @@ describe('index', () => { let body = 'Identical to previous version -- not replacing.'; mockDoPostRequest(body); - return rokuDeploy.publish(options).then((result) => { + return rokuDeploy.publish(options as any).then((result) => { expect(result.results.body).to.equal(body); }, () => { assert.fail('Should have resolved promise'); @@ -1002,7 +1002,7 @@ describe('index', () => { mockDoPostRequest(body, 123); try { - await rokuDeploy.publish(options); + await rokuDeploy.publish(options as any); } catch (e) { expect(e).to.be.instanceof(errors.InvalidDeviceResponseCodeError); return; @@ -1015,7 +1015,7 @@ describe('index', () => { mockDoPostRequest('', 401); try { - await rokuDeploy.publish(options); + await rokuDeploy.publish(options as any); } catch (e) { expect(e).to.be.instanceof(errors.UnauthorizedDeviceResponseError); return; @@ -1028,7 +1028,7 @@ describe('index', () => { mockDoPostRequest(null); try { - await rokuDeploy.publish(options); + await rokuDeploy.publish(options as any); } catch (e) { assert.ok('Exception was thrown as expected'); return; @@ -1040,14 +1040,14 @@ describe('index', () => { describe('convertToSquashfs', () => { it('should not return an error if successful', async () => { mockDoPostRequest('Conversion succeeded


Parallel mksquashfs: Using 1 processor'); - await rokuDeploy.convertToSquashfs(options); + await rokuDeploy.convertToSquashfs(options as any); }); it('should return MissingRequiredOptionError if host was not provided', async () => { mockDoPostRequest(); try { options.host = undefined; - await rokuDeploy.convertToSquashfs(options); + await rokuDeploy.convertToSquashfs(options as any); } catch (e) { expect(e).to.be.instanceof(errors.MissingRequiredOptionError); return; @@ -1058,7 +1058,7 @@ describe('index', () => { it('should return ConvertError if converting failed', async () => { mockDoPostRequest(); try { - await rokuDeploy.convertToSquashfs(options); + await rokuDeploy.convertToSquashfs(options as any); } catch (e) { expect(e).to.be.instanceof(errors.ConvertError); return; @@ -1081,7 +1081,7 @@ describe('index', () => { sinon.stub(fsExtra, 'createReadStream').throws(expectedError); let actualError: Error; try { - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); } catch (e) { actualError = e as Error; } @@ -1096,7 +1096,7 @@ describe('index', () => { options.rekeySignedPackage = s`../notReal.pkg`; try { fsExtra.writeFileSync(s`${tempDir}/notReal.pkg`, ''); - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); } finally { fsExtra.removeSync(s`${tempDir}/notReal.pkg`); } @@ -1109,7 +1109,7 @@ describe('index', () => { mockDoPostRequest(body); options.rekeySignedPackage = s`${tempDir}/testSignedPackage.pkg`; - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); }); it('should not return an error if dev ID is set and matches output', async () => { @@ -1117,7 +1117,7 @@ describe('index', () => { Success. `; mockDoPostRequest(body); - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); }); it('should not return an error if dev ID is not set', async () => { @@ -1126,13 +1126,13 @@ describe('index', () => { `; mockDoPostRequest(body); options.devId = undefined; - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); }); it('should throw error if missing rekeySignedPackage option', async () => { try { options.rekeySignedPackage = null; - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); } catch (e) { expect(e).to.be.instanceof(errors.MissingRequiredOptionError); return; @@ -1143,7 +1143,7 @@ describe('index', () => { it('should throw error if missing signingPassword option', async () => { try { options.signingPassword = null; - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); } catch (e) { expect(e).to.be.instanceof(errors.MissingRequiredOptionError); return; @@ -1154,7 +1154,7 @@ describe('index', () => { it('should throw error if response is not parsable', async () => { try { mockDoPostRequest(); - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); } catch (e) { expect(e).to.be.instanceof(errors.UnparsableDeviceResponseError); return; @@ -1168,7 +1168,7 @@ describe('index', () => { Invalid public key. `; mockDoPostRequest(body); - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); } catch (e) { expect(e).to.be.instanceof(errors.FailedDeviceResponseError); return; @@ -1184,7 +1184,7 @@ describe('index', () => { mockDoPostRequest(body); options.devId = '45fdc2019903ac333ff624b0b2cddd2c733c3e74'; - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); } catch (e) { expect(e).to.be.instanceof(errors.UnknownDeviceResponseError); return; @@ -1201,7 +1201,7 @@ describe('index', () => { it('should return our error if signingPassword is not supplied', async () => { options.signingPassword = undefined; await expectThrowsAsync(async () => { - await rokuDeploy.signExistingPackage(options); + await rokuDeploy.signExistingPackage(options as any); }, 'Must supply signingPassword'); }); @@ -1213,7 +1213,7 @@ describe('index', () => { process.nextTick(callback, error); return {} as any; }); - await rokuDeploy.signExistingPackage(options); + await rokuDeploy.signExistingPackage(options as any); } catch (e) { expect(e).to.equal(error); return; @@ -1224,7 +1224,7 @@ describe('index', () => { it('should return our error if it received invalid data', async () => { try { mockDoPostRequest(null); - await rokuDeploy.signExistingPackage(options); + await rokuDeploy.signExistingPackage(options as any); } catch (e) { expect(e).to.be.instanceof(errors.UnparsableDeviceResponseError); return; @@ -1240,7 +1240,7 @@ describe('index', () => { mockDoPostRequest(body); await expectThrowsAsync( - rokuDeploy.signExistingPackage(options), + rokuDeploy.signExistingPackage(options as any), 'Invalid Password.' ); }); @@ -1251,14 +1251,14 @@ describe('index', () => { node.appendChild(pkgDiv);`; mockDoPostRequest(body); - let pkgPath = await rokuDeploy.signExistingPackage(options); + let pkgPath = await rokuDeploy.signExistingPackage(options as any); expect(pkgPath).to.equal('pkgs//P6953175d5df120c0069c53de12515b9a.pkg'); }); it('should return our fallback error if neither error or package link was detected', async () => { mockDoPostRequest(); await expectThrowsAsync( - rokuDeploy.signExistingPackage(options), + rokuDeploy.signExistingPackage(options as any), 'Unknown error signing package' ); }); @@ -1270,13 +1270,13 @@ describe('index', () => { files: [ 'manifest' ] - }); + } as any); expectPathExists(`${stagingDir}`); }); it('should support overriding the staging folder', async () => { await rokuDeploy.prepublishToStaging({ - ...options, + ...options as any, files: ['manifest'], stagingDir: `${tempDir}/custom-out-dir` }); @@ -1292,7 +1292,7 @@ describe('index', () => { 'manifest', 'source/main.brs' ]; - await rokuDeploy.prepublishToStaging(options); + await rokuDeploy.prepublishToStaging(options as any); expectPathExists(`${stagingDir}/manifest`); expectPathExists(`${stagingDir}/source/main.brs`); }); @@ -1309,7 +1309,7 @@ describe('index', () => { dest: 'source' } ]; - await rokuDeploy.prepublishToStaging(options); + await rokuDeploy.prepublishToStaging(options as any); expectPathExists(`${stagingDir}/source/main.brs`); }); @@ -1332,7 +1332,7 @@ describe('index', () => { dest: 'source/main.brs' } ]; - await rokuDeploy.prepublishToStaging(options); + await rokuDeploy.prepublishToStaging(options as any); expectPathExists(`${stagingDir}/manifest`); expectPathExists(`${stagingDir}/source/main.brs`); }); @@ -1352,7 +1352,7 @@ describe('index', () => { dest: 'source/renamed.brs' } ]; - await rokuDeploy.prepublishToStaging(options); + await rokuDeploy.prepublishToStaging(options as any); expectPathExists(`${stagingDir}/source/renamed.brs`); }); @@ -1370,7 +1370,7 @@ describe('index', () => { dest: 'source/renamed.brs' } ]; - await rokuDeploy.prepublishToStaging(options); + await rokuDeploy.prepublishToStaging(options as any); expectPathExists(`${stagingDir}/manifest`); }); @@ -1386,7 +1386,7 @@ describe('index', () => { ]; options.retainStagingFolder = true; console.log('before'); - await rokuDeploy.prepublishToStaging(options); + await rokuDeploy.prepublishToStaging(options as any); console.log('after'); expectPathExists(s`${stagingDir}/components/loader/loader.brs`); expectPathNotExists(s`${stagingDir}/components/scenes/home/home.brs`); @@ -1406,7 +1406,7 @@ describe('index', () => { 'components/**/*', '!components/scenes/**/*' ] - }); + } as any); expectPathExists(`${stagingDir}/components/Loader/Loader.brs`); expectPathNotExists(`${stagingDir}/components/scenes/Home/Home.brs`); }); @@ -1418,7 +1418,7 @@ describe('index', () => { ]; options.retainStagingFolder = true; try { - await rokuDeploy.prepublishToStaging(options); + await rokuDeploy.prepublishToStaging(options as any); expect(true).to.be.false; } catch (e) { expect(true).to.be.true; @@ -1434,7 +1434,7 @@ describe('index', () => { dest: 'resources' } ]; - await rokuDeploy.prepublishToStaging(options); + await rokuDeploy.prepublishToStaging(options as any); expectPathExists(`${stagingDir}/resources/images/fhd/image.jpg`); }); @@ -1452,7 +1452,7 @@ describe('index', () => { dest: 'resources' } ]; - await rokuDeploy.prepublishToStaging(options); + await rokuDeploy.prepublishToStaging(options as any); expectPathExists(s`${stagingDir}/resources/images/fhd/image.jpg`); expectPathNotExists(s`${stagingDir}/resources/image.jpg`); }); @@ -1543,7 +1543,7 @@ describe('index', () => { dest: s`renamed_test.md` }]); - await rokuDeploy.prepublishToStaging(opts); + await rokuDeploy.prepublishToStaging(opts as any); let stagedFilePath = s`${stagingDirValue}/renamed_test.md`; expectPathExists(stagedFilePath); let fileContents = await fsExtra.readFile(stagedFilePath); @@ -1588,7 +1588,7 @@ describe('index', () => { dest: s`source/main.brs` }]); - await rokuDeploy.prepublishToStaging(opts); + await rokuDeploy.prepublishToStaging(opts as any); expect(fsExtra.pathExistsSync(`${stagingPath}/source/lib/promise/promise.brs`)); }); }); @@ -1730,7 +1730,7 @@ describe('index', () => { writeFiles(rootDir, ['manifest']); - let result = await rokuDeploy.deploy(options); + let result = await rokuDeploy.deploy(options as any); expect(result).not.to.be.undefined; }); @@ -1745,7 +1745,7 @@ describe('index', () => { ...options, //something in the previous test is locking the default output zip file. We should fix that at some point... outDir: s`${tempDir}/test1` - }); + } as any); expect(result).not.to.be.undefined; }); @@ -1754,7 +1754,7 @@ describe('index', () => { options.deleteInstalledChannel = true; mockDoPostRequest(); - await rokuDeploy.deploy(options); + await rokuDeploy.deploy(options as any); expect(spy.called).to.equal(true); }); @@ -1764,7 +1764,7 @@ describe('index', () => { options.deleteInstalledChannel = false; mockDoPostRequest(); - await rokuDeploy.deploy(options); + await rokuDeploy.deploy(options as any); expect(spy.notCalled).to.equal(true); }); @@ -3002,7 +3002,7 @@ describe('index', () => { files: [ 'source/main.brs' ] - }); + } as any); expectPathExists(s`${stagingDir}/source/main.brs`); expect(count).to.be.greaterThan(4); }); @@ -3278,7 +3278,7 @@ describe('index', () => { //this should not fail let pkgFilePath = await rokuDeploy.deployAndSignPackage({ retainStagingDir: false - }); + } as any); //the return value should equal what retrieveSignedPackage returned. expect(pkgFilePath).to.equal('some_local_path'); @@ -3289,12 +3289,12 @@ describe('index', () => { //call it again, but specify true for retainStagingDir await rokuDeploy.deployAndSignPackage({ retainStagingDir: true - }); + } as any); //call count should NOT increase expect(stub.getCalls()).to.be.lengthOf(1); //call it again, but don't specify retainStagingDir at all (it should default to FALSE) - await rokuDeploy.deployAndSignPackage({}); + await rokuDeploy.deployAndSignPackage({} as any); //call count should NOT increase expect(stub.getCalls()).to.be.lengthOf(2); }); @@ -3302,7 +3302,7 @@ describe('index', () => { it('converts to squashfs if we request it to', async () => { options.convertToSquashfs = true; let stub = sinon.stub(rokuDeploy, 'convertToSquashfs').returns(Promise.resolve(null)); - await rokuDeploy.deployAndSignPackage(options); + await rokuDeploy.deployAndSignPackage(options as any); expect(stub.getCalls()).to.be.lengthOf(1); }); }); diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 9d84358..480e6df 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -36,8 +36,8 @@ export class RokuDeploy { * Copies all of the referenced files to the staging folder * @param options */ - public async prepublishToStaging(options: RokuDeployOptions) { - options = this.getOptions(options); + public async prepublishToStaging(options: PrepublushingOptions) { + options = this.getOptions(options) as any; //clean the staging directory await this.fsExtra.remove(options.stagingDir); @@ -105,13 +105,13 @@ export class RokuDeploy { * Given an already-populated staging folder, create a zip archive of it and copy it to the output folder * @param options */ - public async zipPackage(options: RokuDeployOptions) { - options = this.getOptions(options); + public async zipPackage(options: ZipOptions) { + options = this.getOptions(options) as any; //make sure the output folder exists await this.fsExtra.ensureDir(options.outDir); - let zipFilePath = this.getOutputZipFilePath(options); + let zipFilePath = this.getOutputZipFilePath(options as any); //ensure the manifest file exists in the staging folder if (!await util.fileExistsCaseInsensitive(`${options.stagingDir}/manifest`)) { @@ -131,10 +131,10 @@ export class RokuDeploy { * Create a zip folder containing all of the specified roku project files. * @param options */ - public async createPackage(options: RokuDeployOptions, beforeZipCallback?: (info: BeforeZipCallbackInfo) => Promise | void) { - options = this.getOptions(options); + public async createPackage(options: CreatePackageOptions, beforeZipCallback?: (info: BeforeZipCallbackInfo) => Promise | void) { + options = this.getOptions(options) as any; - await this.prepublishToStaging(options); + await this.prepublishToStaging(options as any); let manifestPath = util.standardizePath(`${options.stagingDir}/manifest`); let parsedManifest = await this.parseManifest(manifestPath); @@ -154,7 +154,7 @@ export class RokuDeploy { await Promise.resolve(beforeZipCallback(info)); } - await this.zipPackage(options); + await this.zipPackage(options as any); } /** @@ -374,8 +374,8 @@ export class RokuDeploy { })); } - private generateBaseRequestOptions(requestPath: string, options: RokuDeployOptions, formData = {} as T): requestType.OptionsWithUrl { - options = this.getOptions(options); + private generateBaseRequestOptions(requestPath: string, options: BaseOptions, formData = {} as T): requestType.OptionsWithUrl { + options = this.getOptions(options) as any; let url = `http://${options.host}:${options.packagePort}/${requestPath}`; let baseRequestOptions = { url: url, @@ -413,15 +413,15 @@ export class RokuDeploy { * Publish a pre-existing packaged zip file to a remote Roku. * @param options */ - public async publish(options: RokuDeployOptions): Promise<{ message: string; results: any }> { - options = this.getOptions(options); + public async publish(options: PublishOptions): Promise<{ message: string; results: any }> { + options = this.getOptions(options) as any; if (!options.host) { throw new errors.MissingRequiredOptionError('must specify the host for the Roku device'); } //make sure the outDir exists await this.fsExtra.ensureDir(options.outDir); - let zipFilePath = this.getOutputZipFilePath(options); + let zipFilePath = this.getOutputZipFilePath(options as any); let readStream: _fsExtra.ReadStream; try { if ((await this.fsExtra.pathExists(zipFilePath)) === false) { @@ -433,7 +433,7 @@ export class RokuDeploy { readStream.on('open', resolve); }); - let requestOptions = this.generateBaseRequestOptions('plugin_install', options, { + let requestOptions = this.generateBaseRequestOptions('plugin_install', options as any, { mysubmit: 'Replace', archive: readStream }); @@ -498,12 +498,12 @@ export class RokuDeploy { * Converts existing loaded package to squashfs for faster loading packages * @param options */ - public async convertToSquashfs(options: RokuDeployOptions) { - options = this.getOptions(options); + public async convertToSquashfs(options: SquashfsOptions) { + options = this.getOptions(options) as any; if (!options.host) { throw new errors.MissingRequiredOptionError('must specify the host for the Roku device'); } - let requestOptions = this.generateBaseRequestOptions('plugin_install', options, { + let requestOptions = this.generateBaseRequestOptions('plugin_install', options as any, { archive: '', mysubmit: 'Convert to squashfs' }); @@ -518,8 +518,8 @@ export class RokuDeploy { * resign Roku Device with supplied pkg and * @param options */ - public async rekeyDevice(options: RokuDeployOptions) { - options = this.getOptions(options); + public async rekeyDevice(options: RekeyDeviceOptions) { + options = this.getOptions(options) as any; if (!options.rekeySignedPackage) { throw new errors.MissingRequiredOptionError('Must supply rekeySignedPackage'); } @@ -532,7 +532,7 @@ export class RokuDeploy { if (!path.isAbsolute(options.rekeySignedPackage)) { rekeySignedPackagePath = path.join(options.rootDir, options.rekeySignedPackage); } - let requestOptions = this.generateBaseRequestOptions('plugin_inspect', options, { + let requestOptions = this.generateBaseRequestOptions('plugin_inspect', options as any, { mysubmit: 'Rekey', passwd: options.signingPassword, archive: null as _fsExtra.ReadStream @@ -571,8 +571,8 @@ export class RokuDeploy { * Sign a pre-existing package using Roku and return path to retrieve it * @param options */ - public async signExistingPackage(options: RokuDeployOptions): Promise { - options = this.getOptions(options); + public async signExistingPackage(options: SignExistingPackageOptions): Promise { + options = this.getOptions(options) as any; if (!options.signingPassword) { throw new errors.MissingRequiredOptionError('Must supply signingPassword'); } @@ -580,7 +580,7 @@ export class RokuDeploy { let parsedManifest = await this.parseManifest(manifestPath); let appName = parsedManifest.title + '/' + parsedManifest.major_version + '.' + parsedManifest.minor_version; - let requestOptions = this.generateBaseRequestOptions('plugin_package', options, { + let requestOptions = this.generateBaseRequestOptions('plugin_package', options as any, { mysubmit: 'Package', pkg_time: (new Date()).getTime(), //eslint-disable-line camelcase passwd: options.signingPassword, @@ -607,11 +607,11 @@ export class RokuDeploy { * @param pkgPath * @param options */ - public async retrieveSignedPackage(pkgPath: string, options: RokuDeployOptions): Promise { + public async retrieveSignedPackage(pkgPath: string, options: RetrieveSignedPackageOptions): Promise { options = this.getOptions(options); - let requestOptions = this.generateBaseRequestOptions(pkgPath, options); + let requestOptions = this.generateBaseRequestOptions(pkgPath, options as any); - let pkgFilePath = this.getOutputPkgFilePath(options); + let pkgFilePath = this.getOutputPkgFilePath(options as any); return this.getToFile(requestOptions, pkgFilePath); } @@ -708,9 +708,9 @@ export class RokuDeploy { * Create a zip of the project, and then publish to the target Roku device * @param options */ - public async deploy(options?: RokuDeployOptions, beforeZipCallback?: (info: BeforeZipCallbackInfo) => void) { - options = this.getOptions(options); - await this.createPackage(options, beforeZipCallback); + public async deploy(options?: DeployOptions, beforeZipCallback?: (info: BeforeZipCallbackInfo) => void) { + options = this.getOptions(options) as any; + await this.createPackage(options as any, beforeZipCallback); if (options.deleteInstalledChannel) { try { await this.deleteInstalledChannel(options); @@ -718,7 +718,7 @@ export class RokuDeploy { // note we don't report the error; as we don't actually care that we could not deploy - it's just useless noise to log it. } } - let result = await this.publish(options); + let result = await this.publish(options as any); return result; } @@ -726,10 +726,10 @@ export class RokuDeploy { * Deletes any installed dev channel on the target Roku device * @param options */ - public async deleteInstalledChannel(options?: RokuDeployOptions) { + public async deleteInstalledChannel(options?: DeleteChannelOptions) { options = this.getOptions(options); - let deleteOptions = this.generateBaseRequestOptions('plugin_install', options); + let deleteOptions = this.generateBaseRequestOptions('plugin_install', options as any); deleteOptions.formData = { mysubmit: 'Delete', archive: '' @@ -747,7 +747,7 @@ export class RokuDeploy { // Ask for the device to make an image let createScreenshotResult = await this.doPostRequest({ - ...this.generateBaseRequestOptions('plugin_inspect', options), + ...this.generateBaseRequestOptions('plugin_inspect', options as any), formData: { mysubmit: 'Screenshot', archive: '' @@ -759,7 +759,7 @@ export class RokuDeploy { if (imageUrlOnDevice) { saveFilePath = util.standardizePath(path.join(options.outDir, options.outFile + imageExt)); - await this.getToFile(this.generateBaseRequestOptions(imageUrlOnDevice, options), saveFilePath); + await this.getToFile(this.generateBaseRequestOptions(imageUrlOnDevice, options as any), saveFilePath); } else { throw new Error('No screen shot url returned from device'); } @@ -790,17 +790,17 @@ export class RokuDeploy { * executes sames steps as deploy and signs the package and stores it in the out folder * @param options */ - public async deployAndSignPackage(options?: RokuDeployOptions, beforeZipCallback?: (info: BeforeZipCallbackInfo) => void): Promise { - options = this.getOptions(options); + public async deployAndSignPackage(options?: DeployAndSignPackageOptions, beforeZipCallback?: (info: BeforeZipCallbackInfo) => void): Promise { + options = this.getOptions(options) as any; let retainStagingDirInitialValue = options.retainStagingDir; options.retainStagingDir = true; - await this.deploy(options, beforeZipCallback); + await this.deploy(options as any, beforeZipCallback); if (options.convertToSquashfs) { - await this.convertToSquashfs(options); + await this.convertToSquashfs(options as any); } - let remotePkgPath = await this.signExistingPackage(options); + let remotePkgPath = await this.signExistingPackage(options as any); let localPkgFilePath = await this.retrieveSignedPackage(remotePkgPath, options); if (retainStagingDirInitialValue !== true) { await this.fsExtra.remove(options.stagingDir); @@ -891,8 +891,8 @@ export class RokuDeploy { * Centralizes getting output zip file path based on passed in options * @param options */ - public getOutputZipFilePath(options: RokuDeployOptions) { - options = this.getOptions(options); + public getOutputZipFilePath(options: ZipPathOptions) { + options = this.getOptions(options) as any; let zipFileName = options.outFile; if (!zipFileName.toLowerCase().endsWith('.zip')) { @@ -908,8 +908,8 @@ export class RokuDeploy { * Centralizes getting output pkg file path based on passed in options * @param options */ - public getOutputPkgFilePath(options?: RokuDeployOptions) { - options = this.getOptions(options); + public getOutputPkgFilePath(options?: OutputPkgFilePathOptions) { + options = this.getOptions(options) as any; let pkgFileName = options.outFile; if (pkgFileName.toLowerCase().endsWith('.zip')) { @@ -989,7 +989,7 @@ export class RokuDeploy { } } - public async getDevId(options?: RokuDeployOptions) { + public async getDevId(options?: DevIdOptions) { const deviceInfo = await this.getDeviceInfo(options as any); return deviceInfo['keyed-developer-id']; } @@ -1167,3 +1167,77 @@ export interface GetDeviceInfoOptions { */ enhance?: boolean; } + +export interface PrepublushingOptions { + files: FileEntry[]; + stagingDir: string; + rootDir: string; +} + +export interface ZipOptions { + stagingDir: string; + retainStagingDir: boolean; + outDir: string; +} + +export interface CreatePackageOptions { + stagingDir: string; + incrementBuildNumber: boolean; +} + +export interface PublishOptions { + host: string; + outDir: string; + remoteDebug: boolean; + remoteDebugConnectEarly: boolean; + failOnCompileError: boolean; + retainDeploymentArchive: boolean; +} + +export interface BaseOptions { + host: string; + packagePort: number; + timeout: number; + username: string; + password: string; +} + +export interface SquashfsOptions { + host: string; +} + +export interface RekeyDeviceOptions { + rekeySignedPackage: string; + signingPassword: string; + rootDir: string; + devId: string; +} + +export interface SignExistingPackageOptions { + signingPassword: string; + stagingDir: string; +} + +type RetrieveSignedPackageOptions = RokuDeployOptions; +type DeleteChannelOptions = RokuDeployOptions; + +export interface ZipPathOptions { + outFile: string; + outDir: string; +} + +export interface DeployOptions { + deleteInstalledChannel: boolean; +} + +export interface DeployAndSignPackageOptions { + retainStagingDir: boolean; + convertToSquashfs: boolean; + stagingDir: string; +} +export interface OutputPkgFilePathOptions { + outFile: string; + outDir: string; +} + +type DevIdOptions = RokuDeployOptions; diff --git a/src/device.spec.ts b/src/device.spec.ts index d7b3ebe..d5823f1 100644 --- a/src/device.spec.ts +++ b/src/device.spec.ts @@ -82,7 +82,7 @@ describe('device', function device() { describe('deployAndSignPackage', () => { it('works', async () => { await rokuDeploy.deleteInstalledChannel(options); - await rokuDeploy.rekeyDevice(options); + await rokuDeploy.rekeyDevice(options as any); expectPathExists( await rokuDeploy.deployAndSignPackage(options) ); From 30c03a619858750180fc230079210c16ff435639 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Mon, 13 Nov 2023 17:12:19 +0100 Subject: [PATCH 02/30] variable name changes for different options --- src/RokuDeploy.ts | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 480e6df..b817b30 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -36,7 +36,7 @@ export class RokuDeploy { * Copies all of the referenced files to the staging folder * @param options */ - public async prepublishToStaging(options: PrepublushingOptions) { + public async prepublishToStaging(options: PrepublishToStagingOptions) { options = this.getOptions(options) as any; //clean the staging directory @@ -105,7 +105,7 @@ export class RokuDeploy { * Given an already-populated staging folder, create a zip archive of it and copy it to the output folder * @param options */ - public async zipPackage(options: ZipOptions) { + public async zipPackage(options: ZipPackageOptions) { options = this.getOptions(options) as any; //make sure the output folder exists @@ -498,7 +498,7 @@ export class RokuDeploy { * Converts existing loaded package to squashfs for faster loading packages * @param options */ - public async convertToSquashfs(options: SquashfsOptions) { + public async convertToSquashfs(options: ConvertToSquashfsOptions) { options = this.getOptions(options) as any; if (!options.host) { throw new errors.MissingRequiredOptionError('must specify the host for the Roku device'); @@ -608,7 +608,7 @@ export class RokuDeploy { * @param options */ public async retrieveSignedPackage(pkgPath: string, options: RetrieveSignedPackageOptions): Promise { - options = this.getOptions(options); + options = this.getOptions(options) as any; let requestOptions = this.generateBaseRequestOptions(pkgPath, options as any); let pkgFilePath = this.getOutputPkgFilePath(options as any); @@ -726,7 +726,7 @@ export class RokuDeploy { * Deletes any installed dev channel on the target Roku device * @param options */ - public async deleteInstalledChannel(options?: DeleteChannelOptions) { + public async deleteInstalledChannel(options?: DeleteInstalledChannelOptions) { options = this.getOptions(options); let deleteOptions = this.generateBaseRequestOptions('plugin_install', options as any); @@ -801,7 +801,7 @@ export class RokuDeploy { } let remotePkgPath = await this.signExistingPackage(options as any); - let localPkgFilePath = await this.retrieveSignedPackage(remotePkgPath, options); + let localPkgFilePath = await this.retrieveSignedPackage(remotePkgPath, options as any); if (retainStagingDirInitialValue !== true) { await this.fsExtra.remove(options.stagingDir); } @@ -891,7 +891,7 @@ export class RokuDeploy { * Centralizes getting output zip file path based on passed in options * @param options */ - public getOutputZipFilePath(options: ZipPathOptions) { + public getOutputZipFilePath(options: GetOutputZipFilePathOptions) { options = this.getOptions(options) as any; let zipFileName = options.outFile; @@ -908,7 +908,7 @@ export class RokuDeploy { * Centralizes getting output pkg file path based on passed in options * @param options */ - public getOutputPkgFilePath(options?: OutputPkgFilePathOptions) { + public getOutputPkgFilePath(options?: GetOutputPkgFilePathOptions) { options = this.getOptions(options) as any; let pkgFileName = options.outFile; @@ -989,7 +989,7 @@ export class RokuDeploy { } } - public async getDevId(options?: DevIdOptions) { + public async getDevId(options?: GetDevIdOptions) { const deviceInfo = await this.getDeviceInfo(options as any); return deviceInfo['keyed-developer-id']; } @@ -1168,13 +1168,13 @@ export interface GetDeviceInfoOptions { enhance?: boolean; } -export interface PrepublushingOptions { +export interface PrepublishToStagingOptions { files: FileEntry[]; stagingDir: string; rootDir: string; } -export interface ZipOptions { +export interface ZipPackageOptions { stagingDir: string; retainStagingDir: boolean; outDir: string; @@ -1202,7 +1202,7 @@ export interface BaseOptions { password: string; } -export interface SquashfsOptions { +export interface ConvertToSquashfsOptions { host: string; } @@ -1218,10 +1218,10 @@ export interface SignExistingPackageOptions { stagingDir: string; } -type RetrieveSignedPackageOptions = RokuDeployOptions; -type DeleteChannelOptions = RokuDeployOptions; +type RetrieveSignedPackageOptions = BaseOptions; +type DeleteInstalledChannelOptions = RokuDeployOptions; -export interface ZipPathOptions { +export interface GetOutputZipFilePathOptions { outFile: string; outDir: string; } @@ -1235,9 +1235,9 @@ export interface DeployAndSignPackageOptions { convertToSquashfs: boolean; stagingDir: string; } -export interface OutputPkgFilePathOptions { +export interface GetOutputPkgFilePathOptions { outFile: string; outDir: string; } -type DevIdOptions = RokuDeployOptions; +type GetDevIdOptions = RokuDeployOptions; From 824ecb171dbf38769b6da540078cd741afe4e992 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 13:16:48 +0100 Subject: [PATCH 03/30] Make all changes except a few that are questionable --- src/RokuDeploy.spec.ts | 700 +++++++++++++++++++++++++---------------- src/RokuDeploy.ts | 52 +-- 2 files changed, 462 insertions(+), 290 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index c3823b2..5bc9308 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -54,29 +54,37 @@ describe('index', () => { describe('getOutputPkgFilePath', () => { it('should return correct path if given basename', () => { - options.outFile = 'roku-deploy'; - let outputPath = rokuDeploy.getOutputPkgFilePath(options as any); + let outputPath = rokuDeploy.getOutputPkgFilePath({ + outFile: 'roku-deploy', + outDir: options.outDir + }); expect(outputPath).to.equal(path.join(path.resolve(options.outDir), options.outFile + '.pkg')); }); it('should return correct path if given outFile option ending in .zip', () => { - options.outFile = 'roku-deploy.zip'; - let outputPath = rokuDeploy.getOutputPkgFilePath(options as any); + let outputPath = rokuDeploy.getOutputPkgFilePath({ + outFile: 'roku-deploy.zip', + outDir: options.outDir + }); expect(outputPath).to.equal(path.join(path.resolve(options.outDir), 'roku-deploy.pkg')); }); }); describe('getOutputZipFilePath', () => { it('should return correct path if given basename', () => { - options.outFile = 'roku-deploy'; - let outputPath = rokuDeploy.getOutputZipFilePath(options as any); - expect(outputPath).to.equal(path.join(path.resolve(options.outDir), options.outFile + '.zip')); + let outputPath = rokuDeploy.getOutputZipFilePath({ + outFile: 'roku-deploy', + outDir: outDir + }); + expect(outputPath).to.equal(path.join(path.resolve(outDir), 'roku-deploy.zip')); }); it('should return correct path if given outFile option ending in .zip', () => { - options.outFile = 'roku-deploy.zip'; - let outputPath = rokuDeploy.getOutputZipFilePath(options as any); - expect(outputPath).to.equal(path.join(path.resolve(options.outDir), 'roku-deploy.zip')); + let outputPath = rokuDeploy.getOutputZipFilePath({ + outFile: 'roku-deploy.zip', + outDir: outDir + }); + expect(outputPath).to.equal(path.join(path.resolve(outDir), 'roku-deploy.zip')); }); }); @@ -573,41 +581,49 @@ describe('index', () => { describe('createPackage', () => { it('works with custom stagingDir', async () => { - let opts = { - ...options, + await rokuDeploy.createPackage({ files: [ 'manifest' ], - stagingDir: '.tmp/dist' - }; - await rokuDeploy.createPackage(opts as any); - expectPathExists(rokuDeploy.getOutputZipFilePath(opts as any)); + stagingDir: '.tmp/dist', + outDir: outDir + }); + expectPathExists(rokuDeploy.getOutputZipFilePath({ outDir: outDir })); }); it('should throw error when no files were found to copy', async () => { await assertThrowsAsync(async () => { - options.files = []; - await rokuDeploy.createPackage(options as any); + await rokuDeploy.createPackage({ + files: [], + stagingDir: '.tmp/dist', + outDir: outDir + }); }); }); it('should create package in proper directory', async () => { await rokuDeploy.createPackage({ - ...options, files: [ 'manifest' - ] - } as any); - expectPathExists(rokuDeploy.getOutputZipFilePath(options as any)); + ], + stagingDir: '.tmp/dist', + outDir: outDir + }); + expectPathExists(rokuDeploy.getOutputZipFilePath({ outDir: outDir })); }); it('should only include the specified files', async () => { - const files = ['manifest']; - options.files = files; - await rokuDeploy.createPackage(options as any); - const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath(options as any)); + await rokuDeploy.createPackage({ + files: [ + 'manifest' + ], + stagingDir: '.tmp/dist', + outDir: outDir + }); + const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath({ outDir: outDir })); const zip = await JSZip.loadAsync(data); + const files = ['manifest']; for (const file of files) { const zipFileContents = await zip.file(file.toString()).async('string'); const sourcePath = path.join(options.rootDir, file); @@ -624,10 +640,10 @@ describe('index', () => { 'manifest' ]); await rokuDeploy.createPackage({ - ...options, - //target a subset of the files to make the test faster - files: filePaths - } as any); + files: filePaths, + stagingDir: '.tmp/dist', + outDir: outDir + }); const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath(options as any)); const zip = await JSZip.loadAsync(data); @@ -642,11 +658,11 @@ describe('index', () => { it('should retain the staging directory when told to', async () => { let stagingDirValue = await rokuDeploy.prepublishToStaging({ - ...options, files: [ 'manifest' - ] - } as any); + ], + stagingDir: '.tmp/dist' + }); expectPathExists(stagingDirValue); options.retainStagingDir = true; await rokuDeploy.zipPackage(options as any); @@ -661,7 +677,13 @@ describe('index', () => { expect(info.manifestData.major_version).to.equal('1'); }); - await rokuDeploy.createPackage(options as any, spy); + await rokuDeploy.createPackage({ + files: [ + 'manifest' + ], + stagingDir: '.tmp/dist', + outDir: outDir + }, spy); if (spy.notCalled) { assert.fail('Callback not called'); @@ -672,9 +694,12 @@ describe('index', () => { fsExtra.outputFileSync(`${rootDir}/manifest`, ''); let count = 0; await rokuDeploy.createPackage({ - ...options, - files: ['manifest'] - } as any, (info) => { + files: [ + 'manifest' + ], + stagingDir: '.tmp/dist', + outDir: outDir + }, (info) => { return Promise.resolve().then(() => { count++; }).then(() => { @@ -691,9 +716,12 @@ describe('index', () => { sinon.stub(rokuDeploy, 'zipPackage').returns(Promise.resolve()); let beforeZipInfo: BeforeZipCallbackInfo; await rokuDeploy.createPackage({ - ...options, - files: ['manifest'] - } as any, (info) => { + files: [ + 'manifest' + ], + stagingDir: '.tmp/dist', + outDir: outDir + }, (info) => { beforeZipInfo = info; }); expect(beforeZipInfo.manifestData.build_version).to.not.equal('0'); @@ -703,11 +731,12 @@ describe('index', () => { fsExtra.outputFileSync(`${rootDir}/manifest`, `build_version=0`); options.incrementBuildNumber = false; await rokuDeploy.createPackage({ - ...options, files: [ 'manifest' - ] - } as any, (info) => { + ], + stagingDir: '.tmp/dist', + outDir: outDir + }, (info) => { expect(info.manifestData.build_version).to.equal('0'); }); }); @@ -795,8 +824,6 @@ describe('index', () => { let fileCounter = 1; describe('publish', () => { beforeEach(() => { - options.host = '0.0.0.0'; - //make a dummy output file...we don't care what's in it options.outFile = `temp${fileCounter++}.zip`; try { @@ -811,7 +838,10 @@ describe('index', () => { //the file should exist expect(fsExtra.pathExistsSync(zipPath)).to.be.true; - await rokuDeploy.publish(options as any); + await rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir + }); //the file should still exist expect(fsExtra.pathExistsSync(zipPath)).to.be.true; }); @@ -823,7 +853,11 @@ describe('index', () => { //the file should exist expect(fsExtra.pathExistsSync(zipPath)).to.be.true; - await rokuDeploy.publish({ ...options, retainDeploymentArchive: false } as any); + await rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + retainDeploymentArchive: false + }); //the file should not exist expect(fsExtra.pathExistsSync(zipPath)).to.be.false; //the out folder should also be deleted since it's empty @@ -848,7 +882,11 @@ describe('index', () => { //the file should exist expect(fsExtra.pathExistsSync(zipPath)).to.be.true; - await rokuDeploy.publish({ ...options, retainDeploymentArchive: false } as any); + await rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + retainDeploymentArchive: false + }); //the file should not exist expect(fsExtra.pathExistsSync(zipPath)).to.be.false; //the out folder should also be deleted since it's empty @@ -857,13 +895,22 @@ describe('index', () => { it('fails when the zip file is missing', async () => { options.outFile = 'fileThatDoesNotExist.zip'; await expectThrowsAsync(async () => { - await rokuDeploy.publish(options as any); - }, `Cannot publish because file does not exist at '${rokuDeploy.getOutputZipFilePath(options as any)}'`); + await rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir + }); + }, `Cannot publish because file does not exist at '${rokuDeploy.getOutputZipFilePath({ + outFile: 'roku-deploy', + outDir: outDir + })}'`); }); it('fails when no host is provided', () => { expectPathNotExists('rokudeploy.json'); - return rokuDeploy.publish({ host: undefined } as any).then(() => { + return rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir + }).then(() => { assert.fail('Should not have succeeded'); }, () => { expect(true).to.be.true; @@ -873,7 +920,7 @@ describe('index', () => { it('throws when package upload fails', async () => { //intercept the post requests sinon.stub(request, 'post').callsFake((data: any, callback: any) => { - if (data.url === `http://${options.host}/plugin_install`) { + if (data.url === `http://1.2.3.4/plugin_install`) { process.nextTick(() => { callback(new Error('Failed to publish to server')); }); @@ -884,7 +931,10 @@ describe('index', () => { }); try { - await rokuDeploy.publish(options as any); + await rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir + }); } catch (e) { assert.ok('Exception was thrown as expected'); return; @@ -893,13 +943,16 @@ describe('index', () => { }); it('rejects as CompileError when initial replace fails', () => { - options.failOnCompileError = true; mockDoPostRequest(` Install Failure: Compilation Failed. Shell.create('Roku.Message').trigger('Set message type', 'error').trigger('Set message content', 'Install Failure: Compilation Failed').trigger('Render', node); `); - return rokuDeploy.publish(options as any).then(() => { + return rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true + }).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { expect(err).to.be.instanceOf(errors.CompileError); @@ -907,13 +960,16 @@ describe('index', () => { }); it('rejects as CompileError when initial replace fails', () => { - options.failOnCompileError = true; mockDoPostRequest(` Install Failure: Compilation Failed. Shell.create('Roku.Message').trigger('Set message type', 'error').trigger('Set message content', 'Install Failure: Compilation Failed').trigger('Render', node); `); - return rokuDeploy.publish(options as any).then(() => { + return rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true + }).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { expect(err).to.be.instanceOf(errors.CompileError); @@ -921,11 +977,14 @@ describe('index', () => { }); it('rejects when response contains compile error wording', () => { - options.failOnCompileError = true; let body = 'Install Failure: Compilation Failed.'; mockDoPostRequest(body); - return rokuDeploy.publish(options as any).then(() => { + return rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true + }).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { expect(err.message).to.equal('Compile error'); @@ -934,10 +993,13 @@ describe('index', () => { }); it('rejects when response contains invalid password status code', () => { - options.failOnCompileError = true; mockDoPostRequest('', 401); - return rokuDeploy.publish(options as any).then(() => { + return rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true + }).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { expect(err.message).to.equal('Unauthorized. Please verify username and password for target Roku.'); @@ -946,10 +1008,13 @@ describe('index', () => { }); it('handles successful deploy', () => { - options.failOnCompileError = true; mockDoPostRequest(); - return rokuDeploy.publish(options as any).then((result) => { + return rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true + }).then((result) => { expect(result.message).to.equal('Successful deploy'); }, () => { assert.fail('Should not have rejected the promise'); @@ -957,11 +1022,14 @@ describe('index', () => { }); it('handles successful deploy with remoteDebug', () => { - options.failOnCompileError = true; - options.remoteDebug = true; const stub = mockDoPostRequest(); - return rokuDeploy.publish(options as any).then((result) => { + return rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true, + remoteDebug: true + }).then((result) => { expect(result.message).to.equal('Successful deploy'); expect(stub.getCall(0).args[0].formData.remotedebug).to.eql('1'); }, () => { @@ -970,12 +1038,15 @@ describe('index', () => { }); it('handles successful deploy with remotedebug_connect_early', () => { - options.failOnCompileError = true; - options.remoteDebug = true; - options.remoteDebugConnectEarly = true; const stub = mockDoPostRequest(); - return rokuDeploy.publish(options as any).then((result) => { + return rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true, + remoteDebug: true, + remoteDebugConnectEarly: true + }).then((result) => { expect(result.message).to.equal('Successful deploy'); expect(stub.getCall(0).args[0].formData.remotedebug_connect_early).to.eql('1'); }, () => { @@ -984,12 +1055,14 @@ describe('index', () => { }); it('Does not reject when response contains compile error wording but config is set to ignore compile warnings', () => { - options.failOnCompileError = false; - let body = 'Identical to previous version -- not replacing.'; mockDoPostRequest(body); - return rokuDeploy.publish(options as any).then((result) => { + return rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: false + }).then((result) => { expect(result.results.body).to.equal(body); }, () => { assert.fail('Should have resolved promise'); @@ -997,12 +1070,15 @@ describe('index', () => { }); it('rejects when response is unknown status code', async () => { - options.failOnCompileError = true; let body = 'Identical to previous version -- not replacing.'; mockDoPostRequest(body, 123); try { - await rokuDeploy.publish(options as any); + await rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true + }); } catch (e) { expect(e).to.be.instanceof(errors.InvalidDeviceResponseCodeError); return; @@ -1011,11 +1087,14 @@ describe('index', () => { }); it('rejects when user is unauthorized', async () => { - options.failOnCompileError = true; mockDoPostRequest('', 401); try { - await rokuDeploy.publish(options as any); + await rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true + }); } catch (e) { expect(e).to.be.instanceof(errors.UnauthorizedDeviceResponseError); return; @@ -1024,11 +1103,14 @@ describe('index', () => { }); it('rejects when encountering an undefined response', async () => { - options.failOnCompileError = true; mockDoPostRequest(null); try { - await rokuDeploy.publish(options as any); + await rokuDeploy.publish({ + host: '1.2.3.4', + outDir: outDir, + failOnCompileError: true + }); } catch (e) { assert.ok('Exception was thrown as expected'); return; @@ -1040,14 +1122,14 @@ describe('index', () => { describe('convertToSquashfs', () => { it('should not return an error if successful', async () => { mockDoPostRequest('Conversion succeeded


Parallel mksquashfs: Using 1 processor'); - await rokuDeploy.convertToSquashfs(options as any); + await rokuDeploy.convertToSquashfs({ host: options.host }); }); it('should return MissingRequiredOptionError if host was not provided', async () => { mockDoPostRequest(); try { options.host = undefined; - await rokuDeploy.convertToSquashfs(options as any); + await rokuDeploy.convertToSquashfs({ host: options.host }); } catch (e) { expect(e).to.be.instanceof(errors.MissingRequiredOptionError); return; @@ -1058,7 +1140,7 @@ describe('index', () => { it('should return ConvertError if converting failed', async () => { mockDoPostRequest(); try { - await rokuDeploy.convertToSquashfs(options as any); + await rokuDeploy.convertToSquashfs({ host: options.host }); } catch (e) { expect(e).to.be.instanceof(errors.ConvertError); return; @@ -1081,7 +1163,12 @@ describe('index', () => { sinon.stub(fsExtra, 'createReadStream').throws(expectedError); let actualError: Error; try { - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: options.rekeySignedPackage, + signingPassword: options.signingPassword, + rootDir: options.rootDir, + devId: options.devId + }); } catch (e) { actualError = e as Error; } @@ -1093,10 +1180,14 @@ describe('index', () => { Success. `; mockDoPostRequest(body); - options.rekeySignedPackage = s`../notReal.pkg`; try { fsExtra.writeFileSync(s`${tempDir}/notReal.pkg`, ''); - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: s`../notReal.pkg`, + signingPassword: options.signingPassword, + rootDir: options.rootDir, + devId: options.devId + }); } finally { fsExtra.removeSync(s`${tempDir}/notReal.pkg`); } @@ -1107,9 +1198,12 @@ describe('index', () => { Success. `; mockDoPostRequest(body); - - options.rekeySignedPackage = s`${tempDir}/testSignedPackage.pkg`; - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: s`${tempDir}/testSignedPackage.pkg`, + signingPassword: options.signingPassword, + rootDir: options.rootDir, + devId: options.devId + }); }); it('should not return an error if dev ID is set and matches output', async () => { @@ -1117,7 +1211,12 @@ describe('index', () => { Success. `; mockDoPostRequest(body); - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: options.rekeySignedPackage, + signingPassword: options.signingPassword, + rootDir: options.rootDir, + devId: options.devId + }); }); it('should not return an error if dev ID is not set', async () => { @@ -1125,14 +1224,22 @@ describe('index', () => { Success. `; mockDoPostRequest(body); - options.devId = undefined; - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: options.rekeySignedPackage, + signingPassword: options.signingPassword, + rootDir: options.rootDir, + devId: undefined + }); }); it('should throw error if missing rekeySignedPackage option', async () => { try { - options.rekeySignedPackage = null; - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: null, + signingPassword: options.signingPassword, + rootDir: options.rootDir, + devId: options.devId + }); } catch (e) { expect(e).to.be.instanceof(errors.MissingRequiredOptionError); return; @@ -1142,8 +1249,12 @@ describe('index', () => { it('should throw error if missing signingPassword option', async () => { try { - options.signingPassword = null; - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: options.rekeySignedPackage, + signingPassword: null, + rootDir: options.rootDir, + devId: options.devId + }); } catch (e) { expect(e).to.be.instanceof(errors.MissingRequiredOptionError); return; @@ -1154,7 +1265,12 @@ describe('index', () => { it('should throw error if response is not parsable', async () => { try { mockDoPostRequest(); - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: options.rekeySignedPackage, + signingPassword: options.signingPassword, + rootDir: options.rootDir, + devId: options.devId + }); } catch (e) { expect(e).to.be.instanceof(errors.UnparsableDeviceResponseError); return; @@ -1168,7 +1284,12 @@ describe('index', () => { Invalid public key. `; mockDoPostRequest(body); - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: options.rekeySignedPackage, + signingPassword: options.signingPassword, + rootDir: options.rootDir, + devId: options.devId + }); } catch (e) { expect(e).to.be.instanceof(errors.FailedDeviceResponseError); return; @@ -1182,9 +1303,12 @@ describe('index', () => { Success. `; mockDoPostRequest(body); - - options.devId = '45fdc2019903ac333ff624b0b2cddd2c733c3e74'; - await rokuDeploy.rekeyDevice(options as any); + await rokuDeploy.rekeyDevice({ + rekeySignedPackage: options.rekeySignedPackage, + signingPassword: options.signingPassword, + rootDir: options.rootDir, + devId: '45fdc2019903ac333ff624b0b2cddd2c733c3e74' + }); } catch (e) { expect(e).to.be.instanceof(errors.UnknownDeviceResponseError); return; @@ -1199,9 +1323,11 @@ describe('index', () => { }); it('should return our error if signingPassword is not supplied', async () => { - options.signingPassword = undefined; await expectThrowsAsync(async () => { - await rokuDeploy.signExistingPackage(options as any); + await rokuDeploy.signExistingPackage({ + signingPassword: undefined, + stagingDir: options.stagingDir + }); }, 'Must supply signingPassword'); }); @@ -1213,7 +1339,10 @@ describe('index', () => { process.nextTick(callback, error); return {} as any; }); - await rokuDeploy.signExistingPackage(options as any); + await rokuDeploy.signExistingPackage({ + signingPassword: options.signingPassword, + stagingDir: options.stagingDir + }); } catch (e) { expect(e).to.equal(error); return; @@ -1224,7 +1353,10 @@ describe('index', () => { it('should return our error if it received invalid data', async () => { try { mockDoPostRequest(null); - await rokuDeploy.signExistingPackage(options as any); + await rokuDeploy.signExistingPackage({ + signingPassword: options.signingPassword, + stagingDir: options.stagingDir + }); } catch (e) { expect(e).to.be.instanceof(errors.UnparsableDeviceResponseError); return; @@ -1240,7 +1372,10 @@ describe('index', () => { mockDoPostRequest(body); await expectThrowsAsync( - rokuDeploy.signExistingPackage(options as any), + rokuDeploy.signExistingPackage({ + signingPassword: options.signingPassword, + stagingDir: options.stagingDir + }), 'Invalid Password.' ); }); @@ -1251,14 +1386,20 @@ describe('index', () => { node.appendChild(pkgDiv);`; mockDoPostRequest(body); - let pkgPath = await rokuDeploy.signExistingPackage(options as any); + let pkgPath = await rokuDeploy.signExistingPackage({ + signingPassword: options.signingPassword, + stagingDir: options.stagingDir + }); expect(pkgPath).to.equal('pkgs//P6953175d5df120c0069c53de12515b9a.pkg'); }); it('should return our fallback error if neither error or package link was detected', async () => { mockDoPostRequest(); await expectThrowsAsync( - rokuDeploy.signExistingPackage(options as any), + rokuDeploy.signExistingPackage({ + signingPassword: options.signingPassword, + stagingDir: options.stagingDir + }), 'Unknown error signing package' ); }); @@ -1270,13 +1411,12 @@ describe('index', () => { files: [ 'manifest' ] - } as any); + }); expectPathExists(`${stagingDir}`); }); it('should support overriding the staging folder', async () => { await rokuDeploy.prepublishToStaging({ - ...options as any, files: ['manifest'], stagingDir: `${tempDir}/custom-out-dir` }); @@ -1288,11 +1428,12 @@ describe('index', () => { 'manifest', 'source/main.brs' ]); - options.files = [ - 'manifest', - 'source/main.brs' - ]; - await rokuDeploy.prepublishToStaging(options as any); + await rokuDeploy.prepublishToStaging({ + files: [ + 'manifest', + 'source/main.brs' + ] + }); expectPathExists(`${stagingDir}/manifest`); expectPathExists(`${stagingDir}/source/main.brs`); }); @@ -1302,14 +1443,15 @@ describe('index', () => { 'manifest', 'source/main.brs' ]); - options.files = [ - 'manifest', - { - src: 'source/**/*', - dest: 'source' - } - ]; - await rokuDeploy.prepublishToStaging(options as any); + await rokuDeploy.prepublishToStaging({ + files: [ + 'manifest', + { + src: 'source/**/*', + dest: 'source' + } + ] + }); expectPathExists(`${stagingDir}/source/main.brs`); }); @@ -1318,21 +1460,22 @@ describe('index', () => { 'manifest', 'source/main.brs' ]); - options.files = [ - { - src: 'manifest', - dest: '' - }, - { - src: 'source/**/*', - dest: 'source/' - }, - { - src: 'source/main.brs', - dest: 'source/main.brs' - } - ]; - await rokuDeploy.prepublishToStaging(options as any); + await rokuDeploy.prepublishToStaging({ + files: [ + { + src: 'manifest', + dest: '' + }, + { + src: 'source/**/*', + dest: 'source/' + }, + { + src: 'source/main.brs', + dest: 'source/main.brs' + } + ] + }); expectPathExists(`${stagingDir}/manifest`); expectPathExists(`${stagingDir}/source/main.brs`); }); @@ -1342,17 +1485,18 @@ describe('index', () => { 'manifest', 'source/main.brs' ]); - options.files = [ - { - src: 'manifest', - dest: '' - }, - { - src: 'source/main.brs', - dest: 'source/renamed.brs' - } - ]; - await rokuDeploy.prepublishToStaging(options as any); + await rokuDeploy.prepublishToStaging({ + files: [ + { + src: 'manifest', + dest: '' + }, + { + src: 'source/main.brs', + dest: 'source/renamed.brs' + } + ] + }); expectPathExists(`${stagingDir}/source/renamed.brs`); }); @@ -1360,17 +1504,18 @@ describe('index', () => { writeFiles(rootDir, [ 'manifest' ]); - options.files = [ - { - src: `${rootDir}/manifest`, - dest: '' - }, - { - src: 'source/main.brs', - dest: 'source/renamed.brs' - } - ]; - await rokuDeploy.prepublishToStaging(options as any); + await rokuDeploy.prepublishToStaging({ + files: [ + { + src: `${rootDir}/manifest`, + dest: '' + }, + { + src: 'source/main.brs', + dest: 'source/renamed.brs' + } + ] + }); expectPathExists(`${stagingDir}/manifest`); }); @@ -1380,13 +1525,14 @@ describe('index', () => { 'components/loader/loader.brs', 'components/scenes/home/home.brs' ]); - options.files = [ - 'manifest', - 'components/!(scenes)/**/*' - ]; - options.retainStagingFolder = true; console.log('before'); - await rokuDeploy.prepublishToStaging(options as any); + await rokuDeploy.prepublishToStaging({ + files: [ + 'manifest', + 'components/!(scenes)/**/*' + ], + retainStagingFolder: true + }); console.log('after'); expectPathExists(s`${stagingDir}/components/loader/loader.brs`); expectPathNotExists(s`${stagingDir}/components/scenes/home/home.brs`); @@ -1398,27 +1544,28 @@ describe('index', () => { 'components/Loader/Loader.brs', 'components/scenes/Home/Home.brs' ]); - options.retainStagingFolder = true; await rokuDeploy.prepublishToStaging({ - ...options, files: [ + files: [ 'manifest', 'source', 'components/**/*', '!components/scenes/**/*' - ] - } as any); + ], + retainStagingFolder: true + }); expectPathExists(`${stagingDir}/components/Loader/Loader.brs`); expectPathNotExists(`${stagingDir}/components/scenes/Home/Home.brs`); }); it('throws on invalid entries', async () => { - options.files = [ - 'manifest', - {} - ]; - options.retainStagingFolder = true; try { - await rokuDeploy.prepublishToStaging(options as any); + await rokuDeploy.prepublishToStaging({ + files: [ + 'manifest', + {} + ], + retainStagingFolder: true + }); expect(true).to.be.false; } catch (e) { expect(true).to.be.true; @@ -1427,14 +1574,15 @@ describe('index', () => { it('retains subfolder structure when referencing a folder', async () => { fsExtra.outputFileSync(`${rootDir}/flavors/shared/resources/images/fhd/image.jpg`, ''); - options.files = [ - 'manifest', - { - src: 'flavors/shared/resources/**/*', - dest: 'resources' - } - ]; - await rokuDeploy.prepublishToStaging(options as any); + await rokuDeploy.prepublishToStaging({ + files: [ + 'manifest', + { + src: 'flavors/shared/resources/**/*', + dest: 'resources' + } + ] + }); expectPathExists(`${stagingDir}/resources/images/fhd/image.jpg`); }); @@ -1444,15 +1592,16 @@ describe('index', () => { 'flavors/shared/resources/images/fhd/image.jpg', 'resources/image.jpg' ]); - options.files = [ - 'manifest', - { - //the relative structure after /resources should be retained - src: 'flavors/shared/resources/**/*', - dest: 'resources' - } - ]; - await rokuDeploy.prepublishToStaging(options as any); + await rokuDeploy.prepublishToStaging({ + files: [ + 'manifest', + { + //the relative structure after /resources should be retained + src: 'flavors/shared/resources/**/*', + dest: 'resources' + } + ] + }); expectPathExists(s`${stagingDir}/resources/images/fhd/image.jpg`); expectPathNotExists(s`${stagingDir}/resources/image.jpg`); }); @@ -1588,10 +1737,82 @@ describe('index', () => { dest: s`source/main.brs` }]); - await rokuDeploy.prepublishToStaging(opts as any); + await rokuDeploy.prepublishToStaging({ + files: [ + 'manifest', + 'source/**/*' + ], + rootDir: s`${tempDir}/mainProject` + }); expect(fsExtra.pathExistsSync(`${stagingPath}/source/lib/promise/promise.brs`)); }); }); + it('is resilient to file system errors', async () => { + let copy = rokuDeploy.fsExtra.copy; + let count = 0; + + //mock writeFile so we can throw a few errors during the test + sinon.stub(rokuDeploy.fsExtra, 'copy').callsFake((...args) => { + count += 1; + //fail a few times + if (count < 5) { + throw new Error('fake error thrown as part of the unit test'); + } else { + return copy.apply(rokuDeploy.fsExtra, args); + } + }); + + //override the retry milliseconds to make test run faster + let orig = util.tryRepeatAsync.bind(util); + sinon.stub(util, 'tryRepeatAsync').callsFake(async (...args) => { + return orig(args[0], args[1], 0); + }); + + fsExtra.outputFileSync(`${rootDir}/source/main.brs`, ''); + + await rokuDeploy.prepublishToStaging({ + ...options, + files: [ + 'source/main.brs' + ] + } as any); + expectPathExists(s`${stagingDir}/source/main.brs`); + expect(count).to.be.greaterThan(4); + }); + + it('throws underlying error after the max fs error threshold is reached', async () => { + let copy = rokuDeploy.fsExtra.copy; + let count = 0; + + //mock writeFile so we can throw a few errors during the test + sinon.stub(rokuDeploy.fsExtra, 'copy').callsFake((...args) => { + count += 1; + //fail a few times + if (count < 15) { + throw new Error('fake error thrown as part of the unit test'); + } else { + return copy.apply(rokuDeploy.fsExtra, args); + } + }); + + //override the timeout for tryRepeatAsync so this test runs faster + let orig = util.tryRepeatAsync.bind(util); + sinon.stub(util, 'tryRepeatAsync').callsFake(async (...args) => { + return orig(args[0], args[1], 0); + }); + + fsExtra.outputFileSync(`${rootDir}/source/main.brs`, ''); + await expectThrowsAsync( + rokuDeploy.prepublishToStaging({ + rootDir: rootDir, + stagingDir: stagingDir, + files: [ + 'source/main.brs' + ] + }), + 'fake error thrown as part of the unit test' + ); + }); }); describe('normalizeFilesArray', () => { @@ -2937,7 +3158,9 @@ describe('index', () => { } }; let pkgFilePath = await rokuDeploy.retrieveSignedPackage('path_to_pkg', { - outFile: 'roku-deploy-test' + host: '1.2.3.4', + outFile: 'roku-deploy-test', + password: 'aaaa' }); expect(pkgFilePath).to.equal(path.join(process.cwd(), 'out', 'roku-deploy-test.pkg')); }); @@ -2950,7 +3173,9 @@ describe('index', () => { }; await expectThrowsAsync( rokuDeploy.retrieveSignedPackage('path_to_pkg', { - outFile: 'roku-deploy-test' + host: '1.2.3.4', + outFile: 'roku-deploy-test', + password: 'aaaa' }), 'Some error' ); @@ -2966,82 +3191,15 @@ describe('index', () => { }; await expectThrowsAsync( rokuDeploy.retrieveSignedPackage('path_to_pkg', { - outFile: 'roku-deploy-test' + host: '1.2.3.4', + outFile: 'roku-deploy-test', + password: 'aaaa' }), 'Invalid response code: 500' ); }); }); - describe('prepublishToStaging', () => { - it('is resilient to file system errors', async () => { - let copy = rokuDeploy.fsExtra.copy; - let count = 0; - - //mock writeFile so we can throw a few errors during the test - sinon.stub(rokuDeploy.fsExtra, 'copy').callsFake((...args) => { - count += 1; - //fail a few times - if (count < 5) { - throw new Error('fake error thrown as part of the unit test'); - } else { - return copy.apply(rokuDeploy.fsExtra, args); - } - }); - - //override the retry milliseconds to make test run faster - let orig = util.tryRepeatAsync.bind(util); - sinon.stub(util, 'tryRepeatAsync').callsFake(async (...args) => { - return orig(args[0], args[1], 0); - }); - - fsExtra.outputFileSync(`${rootDir}/source/main.brs`, ''); - - await rokuDeploy.prepublishToStaging({ - ...options, - files: [ - 'source/main.brs' - ] - } as any); - expectPathExists(s`${stagingDir}/source/main.brs`); - expect(count).to.be.greaterThan(4); - }); - - it('throws underlying error after the max fs error threshold is reached', async () => { - let copy = rokuDeploy.fsExtra.copy; - let count = 0; - - //mock writeFile so we can throw a few errors during the test - sinon.stub(rokuDeploy.fsExtra, 'copy').callsFake((...args) => { - count += 1; - //fail a few times - if (count < 15) { - throw new Error('fake error thrown as part of the unit test'); - } else { - return copy.apply(rokuDeploy.fsExtra, args); - } - }); - - //override the timeout for tryRepeatAsync so this test runs faster - let orig = util.tryRepeatAsync.bind(util); - sinon.stub(util, 'tryRepeatAsync').callsFake(async (...args) => { - return orig(args[0], args[1], 0); - }); - - fsExtra.outputFileSync(`${rootDir}/source/main.brs`, ''); - await expectThrowsAsync( - rokuDeploy.prepublishToStaging({ - rootDir: rootDir, - stagingDir: stagingDir, - files: [ - 'source/main.brs' - ] - }), - 'fake error thrown as part of the unit test' - ); - }); - }); - describe('checkRequest', () => { it('throws FailedDeviceResponseError when necessary', () => { sinon.stub(rokuDeploy as any, 'getRokuMessagesFromResponseBody').returns({ @@ -3278,7 +3436,7 @@ describe('index', () => { //this should not fail let pkgFilePath = await rokuDeploy.deployAndSignPackage({ retainStagingDir: false - } as any); + }); //the return value should equal what retrieveSignedPackage returned. expect(pkgFilePath).to.equal('some_local_path'); @@ -3289,20 +3447,22 @@ describe('index', () => { //call it again, but specify true for retainStagingDir await rokuDeploy.deployAndSignPackage({ retainStagingDir: true - } as any); + }); //call count should NOT increase expect(stub.getCalls()).to.be.lengthOf(1); //call it again, but don't specify retainStagingDir at all (it should default to FALSE) - await rokuDeploy.deployAndSignPackage({} as any); + await rokuDeploy.deployAndSignPackage({}); //call count should NOT increase expect(stub.getCalls()).to.be.lengthOf(2); }); it('converts to squashfs if we request it to', async () => { - options.convertToSquashfs = true; + // options.convertToSquashfs = true; let stub = sinon.stub(rokuDeploy, 'convertToSquashfs').returns(Promise.resolve(null)); - await rokuDeploy.deployAndSignPackage(options as any); + await rokuDeploy.deployAndSignPackage({ + convertToSquashfs: true + }); expect(stub.getCalls()).to.be.lengthOf(1); }); }); diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index b817b30..60287a3 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -134,7 +134,7 @@ export class RokuDeploy { public async createPackage(options: CreatePackageOptions, beforeZipCallback?: (info: BeforeZipCallbackInfo) => Promise | void) { options = this.getOptions(options) as any; - await this.prepublishToStaging(options as any); + await this.prepublishToStaging(options); let manifestPath = util.standardizePath(`${options.stagingDir}/manifest`); let parsedManifest = await this.parseManifest(manifestPath); @@ -154,7 +154,7 @@ export class RokuDeploy { await Promise.resolve(beforeZipCallback(info)); } - await this.zipPackage(options as any); + await this.zipPackage(options); } /** @@ -374,7 +374,7 @@ export class RokuDeploy { })); } - private generateBaseRequestOptions(requestPath: string, options: BaseOptions, formData = {} as T): requestType.OptionsWithUrl { + private generateBaseRequestOptions(requestPath: string, options: BaseRequestOptions, formData = {} as T): requestType.OptionsWithUrl { options = this.getOptions(options) as any; let url = `http://${options.host}:${options.packagePort}/${requestPath}`; let baseRequestOptions = { @@ -1170,35 +1170,40 @@ export interface GetDeviceInfoOptions { export interface PrepublishToStagingOptions { files: FileEntry[]; - stagingDir: string; - rootDir: string; + stagingDir?: string; + retainStagingFolder?: boolean; + rootDir?: string; } export interface ZipPackageOptions { stagingDir: string; - retainStagingDir: boolean; + retainStagingDir?: boolean; outDir: string; } export interface CreatePackageOptions { + files: FileEntry[]; stagingDir: string; - incrementBuildNumber: boolean; + retainStagingDir?: boolean; + outDir: string; + incrementBuildNumber?: boolean; + rootDir?: string; } export interface PublishOptions { host: string; outDir: string; - remoteDebug: boolean; - remoteDebugConnectEarly: boolean; - failOnCompileError: boolean; - retainDeploymentArchive: boolean; + remoteDebug?: boolean; + remoteDebugConnectEarly?: boolean; + failOnCompileError?: boolean; + retainDeploymentArchive?: boolean; } -export interface BaseOptions { +export interface BaseRequestOptions { host: string; - packagePort: number; - timeout: number; - username: string; + packagePort?: number; + timeout?: number; + username?: string; password: string; } @@ -1218,11 +1223,18 @@ export interface SignExistingPackageOptions { stagingDir: string; } -type RetrieveSignedPackageOptions = BaseOptions; +export interface RetrieveSignedPackageOptions { + host: string; + packagePort?: number; + timeout?: number; + username?: string; + password: string; + outFile?: string; +} type DeleteInstalledChannelOptions = RokuDeployOptions; export interface GetOutputZipFilePathOptions { - outFile: string; + outFile?: string; outDir: string; } @@ -1231,9 +1243,9 @@ export interface DeployOptions { } export interface DeployAndSignPackageOptions { - retainStagingDir: boolean; - convertToSquashfs: boolean; - stagingDir: string; + retainStagingDir?: boolean; + convertToSquashfs?: boolean; + stagingDir?: string; } export interface GetOutputPkgFilePathOptions { outFile: string; From 518b1341dd8ab9ad1b90c2a3a53d17afe28dcd9b Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 13:58:48 +0100 Subject: [PATCH 04/30] Take out warning since rootDir defaults --- src/RokuDeploy.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 60287a3..71adf54 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -348,9 +348,6 @@ export class RokuDeploy { if (!stagingPath) { throw new Error('stagingPath is required'); } - if (!rootDir) { - throw new Error('rootDir is required'); - } if (!await this.fsExtra.pathExists(rootDir)) { throw new Error(`rootDir does not exist at "${rootDir}"`); } From 49a8aff594686f429dfa9f7661910029994d78b2 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 16:44:30 +0100 Subject: [PATCH 05/30] Make variable optional --- src/RokuDeploy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 07765b8..8ceab80 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -1303,7 +1303,7 @@ export interface GetOutputZipFilePathOptions { } export interface DeployOptions { - deleteInstalledChannel: boolean; + deleteInstalledChannel?: boolean; } export interface DeployAndSignPackageOptions { From caa31d321f78bf6d7b5c3ae2b313c65939bd4c69 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 16:59:18 +0100 Subject: [PATCH 06/30] Make rootDir mandatory, fixes 8 failing tests --- src/RokuDeploy.spec.ts | 82 ++++++++++++++++++++++++++---------------- src/RokuDeploy.ts | 4 +-- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 9817150..2baba38 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -56,17 +56,17 @@ describe('index', () => { it('should return correct path if given basename', () => { let outputPath = rokuDeploy.getOutputPkgFilePath({ outFile: 'roku-deploy', - outDir: options.outDir + outDir: outDir }); - expect(outputPath).to.equal(path.join(path.resolve(options.outDir), options.outFile + '.pkg')); + expect(outputPath).to.equal(path.join(path.resolve(outDir), options.outFile + '.pkg')); }); it('should return correct path if given outFile option ending in .zip', () => { let outputPath = rokuDeploy.getOutputPkgFilePath({ outFile: 'roku-deploy.zip', - outDir: options.outDir + outDir: outDir }); - expect(outputPath).to.equal(path.join(path.resolve(options.outDir), 'roku-deploy.pkg')); + expect(outputPath).to.equal(path.join(path.resolve(outDir), 'roku-deploy.pkg')); }); }); @@ -654,7 +654,8 @@ describe('index', () => { 'manifest' ], stagingDir: '.tmp/dist', - outDir: outDir + outDir: outDir, + rootDir: rootDir }); expectPathExists(rokuDeploy.getOutputZipFilePath({ outDir: outDir })); }); @@ -664,7 +665,8 @@ describe('index', () => { await rokuDeploy.createPackage({ files: [], stagingDir: '.tmp/dist', - outDir: outDir + outDir: outDir, + rootDir: rootDir }); }); }); @@ -675,7 +677,8 @@ describe('index', () => { 'manifest' ], stagingDir: '.tmp/dist', - outDir: outDir + outDir: outDir, + rootDir: rootDir }); expectPathExists(rokuDeploy.getOutputZipFilePath({ outDir: outDir })); }); @@ -686,7 +689,8 @@ describe('index', () => { 'manifest' ], stagingDir: '.tmp/dist', - outDir: outDir + outDir: outDir, + rootDir: rootDir }); const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath({ outDir: outDir })); const zip = await JSZip.loadAsync(data); @@ -710,7 +714,8 @@ describe('index', () => { await rokuDeploy.createPackage({ files: filePaths, stagingDir: '.tmp/dist', - outDir: outDir + outDir: outDir, + rootDir: rootDir }); const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath(options as any)); @@ -729,7 +734,8 @@ describe('index', () => { files: [ 'manifest' ], - stagingDir: '.tmp/dist' + stagingDir: '.tmp/dist', + rootDir: rootDir }); expectPathExists(stagingDirValue); options.retainStagingDir = true; @@ -750,7 +756,8 @@ describe('index', () => { 'manifest' ], stagingDir: '.tmp/dist', - outDir: outDir + outDir: outDir, + rootDir: rootDir }, spy); if (spy.notCalled) { @@ -766,7 +773,8 @@ describe('index', () => { 'manifest' ], stagingDir: '.tmp/dist', - outDir: outDir + outDir: outDir, + rootDir: rootDir }, (info) => { return Promise.resolve().then(() => { count++; @@ -788,7 +796,8 @@ describe('index', () => { 'manifest' ], stagingDir: '.tmp/dist', - outDir: outDir + outDir: outDir, + rootDir: rootDir }, (info) => { beforeZipInfo = info; }); @@ -803,7 +812,8 @@ describe('index', () => { 'manifest' ], stagingDir: '.tmp/dist', - outDir: outDir + outDir: outDir, + rootDir: rootDir }, (info) => { expect(info.manifestData.build_version).to.equal('0'); }); @@ -895,12 +905,12 @@ describe('index', () => { //make a dummy output file...we don't care what's in it options.outFile = `temp${fileCounter++}.zip`; try { - fsExtra.outputFileSync(`${options.outDir}/${options.outFile}`, 'asdf'); + fsExtra.outputFileSync(`${outDir}/${options.outFile}`, 'asdf'); } catch (e) { } }); it('does not delete the archive by default', async () => { - let zipPath = `${options.outDir}/${options.outFile}`; + let zipPath = `${outDir}/${options.outFile}`; mockDoPostRequest(); @@ -915,7 +925,7 @@ describe('index', () => { }); it('deletes the archive when configured', async () => { - let zipPath = `${options.outDir}/${options.outFile}`; + let zipPath = `${outDir}/${options.outFile}`; mockDoPostRequest(); @@ -944,7 +954,7 @@ describe('index', () => { return stream; }); - let zipPath = `${options.outDir}/${options.outFile}`; + let zipPath = `${outDir}/${options.outFile}`; mockDoPostRequest(); @@ -1478,7 +1488,8 @@ describe('index', () => { await rokuDeploy.prepublishToStaging({ files: [ 'manifest' - ] + ], + rootDir: rootDir }); expectPathExists(`${stagingDir}`); }); @@ -1486,7 +1497,8 @@ describe('index', () => { it('should support overriding the staging folder', async () => { await rokuDeploy.prepublishToStaging({ files: ['manifest'], - stagingDir: `${tempDir}/custom-out-dir` + stagingDir: `${tempDir}/custom-out-dir`, + rootDir: rootDir }); expectPathExists(`${tempDir}/custom-out-dir`); }); @@ -1500,7 +1512,8 @@ describe('index', () => { files: [ 'manifest', 'source/main.brs' - ] + ], + rootDir: rootDir }); expectPathExists(`${stagingDir}/manifest`); expectPathExists(`${stagingDir}/source/main.brs`); @@ -1518,7 +1531,8 @@ describe('index', () => { src: 'source/**/*', dest: 'source' } - ] + ], + rootDir: rootDir }); expectPathExists(`${stagingDir}/source/main.brs`); }); @@ -1542,7 +1556,8 @@ describe('index', () => { src: 'source/main.brs', dest: 'source/main.brs' } - ] + ], + rootDir: rootDir }); expectPathExists(`${stagingDir}/manifest`); expectPathExists(`${stagingDir}/source/main.brs`); @@ -1563,7 +1578,8 @@ describe('index', () => { src: 'source/main.brs', dest: 'source/renamed.brs' } - ] + ], + rootDir: rootDir }); expectPathExists(`${stagingDir}/source/renamed.brs`); }); @@ -1582,7 +1598,8 @@ describe('index', () => { src: 'source/main.brs', dest: 'source/renamed.brs' } - ] + ], + rootDir: rootDir }); expectPathExists(`${stagingDir}/manifest`); }); @@ -1599,7 +1616,8 @@ describe('index', () => { 'manifest', 'components/!(scenes)/**/*' ], - retainStagingFolder: true + retainStagingFolder: true, + rootDir: rootDir }); console.log('after'); expectPathExists(s`${stagingDir}/components/loader/loader.brs`); @@ -1619,7 +1637,8 @@ describe('index', () => { 'components/**/*', '!components/scenes/**/*' ], - retainStagingFolder: true + retainStagingFolder: true, + rootDir: rootDir }); expectPathExists(`${stagingDir}/components/Loader/Loader.brs`); expectPathNotExists(`${stagingDir}/components/scenes/Home/Home.brs`); @@ -1632,7 +1651,8 @@ describe('index', () => { 'manifest', {} ], - retainStagingFolder: true + retainStagingFolder: true, + rootDir: rootDir }); expect(true).to.be.false; } catch (e) { @@ -1649,7 +1669,8 @@ describe('index', () => { src: 'flavors/shared/resources/**/*', dest: 'resources' } - ] + ], + rootDir: rootDir }); expectPathExists(`${stagingDir}/resources/images/fhd/image.jpg`); }); @@ -1668,7 +1689,8 @@ describe('index', () => { src: 'flavors/shared/resources/**/*', dest: 'resources' } - ] + ], + rootDir: rootDir }); expectPathExists(s`${stagingDir}/resources/images/fhd/image.jpg`); expectPathNotExists(s`${stagingDir}/resources/image.jpg`); diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 8ceab80..b3bbc12 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -1236,7 +1236,7 @@ export interface PrepublishToStagingOptions { files: FileEntry[]; stagingDir?: string; retainStagingFolder?: boolean; - rootDir?: string; + rootDir: string; } export interface ZipPackageOptions { @@ -1251,7 +1251,7 @@ export interface CreatePackageOptions { retainStagingDir?: boolean; outDir: string; incrementBuildNumber?: boolean; - rootDir?: string; + rootDir: string; } export interface PublishOptions { From 3b4337252e39aff82b0dba9f2b7f602e4e02aceb Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 17:32:47 +0100 Subject: [PATCH 07/30] make stagingDir mandatory for zip package, fixes 1 test --- src/RokuDeploy.spec.ts | 45 ++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 2baba38..aa6cf29 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -624,9 +624,11 @@ describe('index', () => { it('should throw error when manifest is missing', async () => { let err; try { - options.stagingDir = s`${tempDir}/path/to/nowhere`; fsExtra.ensureDirSync(options.stagingDir); - await rokuDeploy.zipPackage(options as any); + await rokuDeploy.zipPackage({ + stagingDir: s`${tempDir}/path/to/nowhere`, + outDir: outDir + }); } catch (e) { err = (e as Error); } @@ -636,8 +638,10 @@ describe('index', () => { it('should throw error when manifest is missing and stagingDir does not exist', async () => { let err; try { - options.stagingDir = s`${tempDir}/path/to/nowhere`; - await rokuDeploy.zipPackage(options as any); + await rokuDeploy.zipPackage({ + stagingDir: s`${tempDir}/path/to/nowhere`, + outDir: outDir + }); } catch (e) { err = (e as Error); } @@ -664,7 +668,7 @@ describe('index', () => { await assertThrowsAsync(async () => { await rokuDeploy.createPackage({ files: [], - stagingDir: '.tmp/dist', + stagingDir: stagingDir, outDir: outDir, rootDir: rootDir }); @@ -676,7 +680,7 @@ describe('index', () => { files: [ 'manifest' ], - stagingDir: '.tmp/dist', + stagingDir: stagingDir, outDir: outDir, rootDir: rootDir }); @@ -688,7 +692,7 @@ describe('index', () => { files: [ 'manifest' ], - stagingDir: '.tmp/dist', + stagingDir: stagingDir, outDir: outDir, rootDir: rootDir }); @@ -713,12 +717,12 @@ describe('index', () => { ]); await rokuDeploy.createPackage({ files: filePaths, - stagingDir: '.tmp/dist', + stagingDir: stagingDir, outDir: outDir, rootDir: rootDir }); - const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath(options as any)); + const data = fsExtra.readFileSync(rokuDeploy.getOutputZipFilePath({ outDir: outDir })); const zip = await JSZip.loadAsync(data); for (const file of filePaths) { @@ -734,12 +738,15 @@ describe('index', () => { files: [ 'manifest' ], - stagingDir: '.tmp/dist', + stagingDir: stagingDir, rootDir: rootDir }); expectPathExists(stagingDirValue); options.retainStagingDir = true; - await rokuDeploy.zipPackage(options as any); + await rokuDeploy.zipPackage({ + retainStagingDir: true, + outDir: outDir + }); expectPathExists(stagingDirValue); }); @@ -755,7 +762,7 @@ describe('index', () => { files: [ 'manifest' ], - stagingDir: '.tmp/dist', + stagingDir: stagingDir, outDir: outDir, rootDir: rootDir }, spy); @@ -772,7 +779,7 @@ describe('index', () => { files: [ 'manifest' ], - stagingDir: '.tmp/dist', + stagingDir: stagingDir, outDir: outDir, rootDir: rootDir }, (info) => { @@ -795,7 +802,7 @@ describe('index', () => { files: [ 'manifest' ], - stagingDir: '.tmp/dist', + stagingDir: stagingDir, outDir: outDir, rootDir: rootDir }, (info) => { @@ -806,14 +813,14 @@ describe('index', () => { it('should not increment the build number if not requested', async () => { fsExtra.outputFileSync(`${rootDir}/manifest`, `build_version=0`); - options.incrementBuildNumber = false; await rokuDeploy.createPackage({ files: [ 'manifest' ], - stagingDir: '.tmp/dist', + stagingDir: stagingDir, outDir: outDir, - rootDir: rootDir + rootDir: rootDir, + incrementBuildNumber: false }, (info) => { expect(info.manifestData.build_version).to.equal('0'); }); @@ -829,11 +836,11 @@ describe('index', () => { describe('generateBaseRequestOptions', () => { it('uses default port', () => { - expect(rokuDeploy['generateBaseRequestOptions']('a_b_c', { host: '1.2.3.4' } as any).url).to.equal('http://1.2.3.4:80/a_b_c'); + expect(rokuDeploy['generateBaseRequestOptions']('a_b_c', { host: '1.2.3.4', password: options.password }).url).to.equal('http://1.2.3.4:80/a_b_c'); }); it('uses overridden port', () => { - expect(rokuDeploy['generateBaseRequestOptions']('a_b_c', { host: '1.2.3.4', packagePort: 999 } as any).url).to.equal('http://1.2.3.4:999/a_b_c'); + expect(rokuDeploy['generateBaseRequestOptions']('a_b_c', { host: '1.2.3.4', packagePort: 999, password: options.password }).url).to.equal('http://1.2.3.4:999/a_b_c'); }); }); From 1b4ed6d0da734c2146be800a2aa4870d9cc221d7 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 17:34:43 +0100 Subject: [PATCH 08/30] forgot 2 lines from last commit message --- src/RokuDeploy.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index aa6cf29..bbd1056 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -742,8 +742,8 @@ describe('index', () => { rootDir: rootDir }); expectPathExists(stagingDirValue); - options.retainStagingDir = true; await rokuDeploy.zipPackage({ + stagingDir: stagingDir, retainStagingDir: true, outDir: outDir }); From 40f5951d8fdeacae7d318d284d52a60da5d0f286 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 17:35:48 +0100 Subject: [PATCH 09/30] Fix 1 more test --- src/RokuDeploy.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index bbd1056..3c862d0 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -794,7 +794,6 @@ describe('index', () => { it('should increment the build number if requested', async () => { fsExtra.outputFileSync(`${rootDir}/manifest`, `build_version=0`); - options.incrementBuildNumber = true; //make the zipping immediately resolve sinon.stub(rokuDeploy, 'zipPackage').returns(Promise.resolve()); let beforeZipInfo: BeforeZipCallbackInfo; @@ -804,7 +803,8 @@ describe('index', () => { ], stagingDir: stagingDir, outDir: outDir, - rootDir: rootDir + rootDir: rootDir, + incrementBuildNumber: true }, (info) => { beforeZipInfo = info; }); From 9a9ea910f0f1a955594ebcf0e522dcafafbb7a01 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 17:55:21 +0100 Subject: [PATCH 10/30] Make outfile mandatory in publishOptions, fixes 12 tests --- src/RokuDeploy.spec.ts | 55 +++++++++++++++++++++++++++--------------- src/RokuDeploy.ts | 1 + 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 3c862d0..37bab4c 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -925,7 +925,8 @@ describe('index', () => { expect(fsExtra.pathExistsSync(zipPath)).to.be.true; await rokuDeploy.publish({ host: '1.2.3.4', - outDir: outDir + outDir: outDir, + outFile: options.outFile }); //the file should still exist expect(fsExtra.pathExistsSync(zipPath)).to.be.true; @@ -933,7 +934,6 @@ describe('index', () => { it('deletes the archive when configured', async () => { let zipPath = `${outDir}/${options.outFile}`; - mockDoPostRequest(); //the file should exist @@ -941,7 +941,8 @@ describe('index', () => { await rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - retainDeploymentArchive: false + retainDeploymentArchive: false, + outFile: options.outFile }); //the file should not exist expect(fsExtra.pathExistsSync(zipPath)).to.be.false; @@ -970,7 +971,8 @@ describe('index', () => { await rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - retainDeploymentArchive: false + retainDeploymentArchive: false, + outFile: options.outFile }); //the file should not exist expect(fsExtra.pathExistsSync(zipPath)).to.be.false; @@ -978,11 +980,11 @@ describe('index', () => { }); it('fails when the zip file is missing', async () => { - options.outFile = 'fileThatDoesNotExist.zip'; await expectThrowsAsync(async () => { await rokuDeploy.publish({ host: '1.2.3.4', - outDir: outDir + outDir: outDir, + outFile: 'fileThatDoesNotExist.zip' }); }, `Cannot publish because file does not exist at '${rokuDeploy.getOutputZipFilePath({ outFile: 'roku-deploy', @@ -993,8 +995,9 @@ describe('index', () => { it('fails when no host is provided', () => { expectPathNotExists('rokudeploy.json'); return rokuDeploy.publish({ - host: '1.2.3.4', - outDir: outDir + host: undefined, + outDir: outDir, + outFile: options.outFile }).then(() => { assert.fail('Should not have succeeded'); }, () => { @@ -1018,7 +1021,8 @@ describe('index', () => { try { await rokuDeploy.publish({ host: '1.2.3.4', - outDir: outDir + outDir: outDir, + outFile: options.outFile }); } catch (e) { assert.ok('Exception was thrown as expected'); @@ -1036,7 +1040,8 @@ describe('index', () => { return rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - failOnCompileError: true + failOnCompileError: true, + outFile: options.outFile }).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { @@ -1053,7 +1058,8 @@ describe('index', () => { return rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - failOnCompileError: true + failOnCompileError: true, + outFile: options.outFile }).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { @@ -1068,7 +1074,8 @@ describe('index', () => { return rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - failOnCompileError: true + failOnCompileError: true, + outFile: options.outFile }).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { @@ -1083,7 +1090,8 @@ describe('index', () => { return rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - failOnCompileError: true + failOnCompileError: true, + outFile: options.outFile }).then(() => { assert.fail('Should not have succeeded due to roku server compilation failure'); }, (err) => { @@ -1098,7 +1106,8 @@ describe('index', () => { return rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - failOnCompileError: true + failOnCompileError: true, + outFile: options.outFile }).then((result) => { expect(result.message).to.equal('Successful deploy'); }, () => { @@ -1113,7 +1122,8 @@ describe('index', () => { host: '1.2.3.4', outDir: outDir, failOnCompileError: true, - remoteDebug: true + remoteDebug: true, + outFile: options.outFile }).then((result) => { expect(result.message).to.equal('Successful deploy'); expect(stub.getCall(0).args[0].formData.remotedebug).to.eql('1'); @@ -1130,7 +1140,8 @@ describe('index', () => { outDir: outDir, failOnCompileError: true, remoteDebug: true, - remoteDebugConnectEarly: true + remoteDebugConnectEarly: true, + outFile: options.outFile }).then((result) => { expect(result.message).to.equal('Successful deploy'); expect(stub.getCall(0).args[0].formData.remotedebug_connect_early).to.eql('1'); @@ -1146,7 +1157,8 @@ describe('index', () => { return rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - failOnCompileError: false + failOnCompileError: false, + outFile: options.outFile }).then((result) => { expect(result.results.body).to.equal(body); }, () => { @@ -1162,7 +1174,8 @@ describe('index', () => { await rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - failOnCompileError: true + failOnCompileError: true, + outFile: options.outFile }); } catch (e) { expect(e).to.be.instanceof(errors.InvalidDeviceResponseCodeError); @@ -1178,7 +1191,8 @@ describe('index', () => { await rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - failOnCompileError: true + failOnCompileError: true, + outFile: options.outFile }); } catch (e) { expect(e).to.be.instanceof(errors.UnauthorizedDeviceResponseError); @@ -1194,7 +1208,8 @@ describe('index', () => { await rokuDeploy.publish({ host: '1.2.3.4', outDir: outDir, - failOnCompileError: true + failOnCompileError: true, + outFile: options.outFile }); } catch (e) { assert.ok('Exception was thrown as expected'); diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index b3bbc12..97a415f 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -1261,6 +1261,7 @@ export interface PublishOptions { remoteDebugConnectEarly?: boolean; failOnCompileError?: boolean; retainDeploymentArchive?: boolean; + outFile: string; } export interface BaseRequestOptions { From 59cf00231a8859ff3685f0c1dba65712e46bd23d Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 17:57:39 +0100 Subject: [PATCH 11/30] fix 1 more test over copying mistake --- src/RokuDeploy.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 37bab4c..ea264d7 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -987,7 +987,7 @@ describe('index', () => { outFile: 'fileThatDoesNotExist.zip' }); }, `Cannot publish because file does not exist at '${rokuDeploy.getOutputZipFilePath({ - outFile: 'roku-deploy', + outFile: 'fileThatDoesNotExist.zip', outDir: outDir })}'`); }); From a41bd949830c88576259f1eb322c78b5fa7db48b Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 18:08:13 +0100 Subject: [PATCH 12/30] added stagingDir to prepublishToStaging tests to get 10 more tests to pass, all are passing now --- src/RokuDeploy.spec.ts | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index ea264d7..e132b93 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -1426,7 +1426,7 @@ describe('index', () => { await expectThrowsAsync(async () => { await rokuDeploy.signExistingPackage({ signingPassword: undefined, - stagingDir: options.stagingDir + stagingDir: stagingDir }); }, 'Must supply signingPassword'); }); @@ -1441,7 +1441,7 @@ describe('index', () => { }); await rokuDeploy.signExistingPackage({ signingPassword: options.signingPassword, - stagingDir: options.stagingDir + stagingDir: stagingDir }); } catch (e) { expect(e).to.equal(error); @@ -1455,7 +1455,7 @@ describe('index', () => { mockDoPostRequest(null); await rokuDeploy.signExistingPackage({ signingPassword: options.signingPassword, - stagingDir: options.stagingDir + stagingDir: stagingDir }); } catch (e) { expect(e).to.be.instanceof(errors.UnparsableDeviceResponseError); @@ -1474,7 +1474,7 @@ describe('index', () => { await expectThrowsAsync( rokuDeploy.signExistingPackage({ signingPassword: options.signingPassword, - stagingDir: options.stagingDir + stagingDir: stagingDir }), 'Invalid Password.' ); @@ -1488,7 +1488,7 @@ describe('index', () => { let pkgPath = await rokuDeploy.signExistingPackage({ signingPassword: options.signingPassword, - stagingDir: options.stagingDir + stagingDir: stagingDir }); expect(pkgPath).to.equal('pkgs//P6953175d5df120c0069c53de12515b9a.pkg'); }); @@ -1498,7 +1498,7 @@ describe('index', () => { await expectThrowsAsync( rokuDeploy.signExistingPackage({ signingPassword: options.signingPassword, - stagingDir: options.stagingDir + stagingDir: stagingDir }), 'Unknown error signing package' ); @@ -1535,7 +1535,8 @@ describe('index', () => { 'manifest', 'source/main.brs' ], - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); expectPathExists(`${stagingDir}/manifest`); expectPathExists(`${stagingDir}/source/main.brs`); @@ -1554,7 +1555,8 @@ describe('index', () => { dest: 'source' } ], - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); expectPathExists(`${stagingDir}/source/main.brs`); }); @@ -1579,7 +1581,8 @@ describe('index', () => { dest: 'source/main.brs' } ], - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); expectPathExists(`${stagingDir}/manifest`); expectPathExists(`${stagingDir}/source/main.brs`); @@ -1601,7 +1604,8 @@ describe('index', () => { dest: 'source/renamed.brs' } ], - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); expectPathExists(`${stagingDir}/source/renamed.brs`); }); @@ -1621,7 +1625,8 @@ describe('index', () => { dest: 'source/renamed.brs' } ], - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); expectPathExists(`${stagingDir}/manifest`); }); @@ -1639,7 +1644,8 @@ describe('index', () => { 'components/!(scenes)/**/*' ], retainStagingFolder: true, - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); console.log('after'); expectPathExists(s`${stagingDir}/components/loader/loader.brs`); @@ -1660,7 +1666,8 @@ describe('index', () => { '!components/scenes/**/*' ], retainStagingFolder: true, - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); expectPathExists(`${stagingDir}/components/Loader/Loader.brs`); expectPathNotExists(`${stagingDir}/components/scenes/Home/Home.brs`); @@ -1674,7 +1681,8 @@ describe('index', () => { {} ], retainStagingFolder: true, - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); expect(true).to.be.false; } catch (e) { @@ -1692,7 +1700,8 @@ describe('index', () => { dest: 'resources' } ], - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); expectPathExists(`${stagingDir}/resources/images/fhd/image.jpg`); }); @@ -1712,7 +1721,8 @@ describe('index', () => { dest: 'resources' } ], - rootDir: rootDir + rootDir: rootDir, + stagingDir: stagingDir }); expectPathExists(s`${stagingDir}/resources/images/fhd/image.jpg`); expectPathNotExists(s`${stagingDir}/resources/image.jpg`); From 1526d681858e36ba28dd298826f430600f8512f0 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 18:21:07 +0100 Subject: [PATCH 13/30] Changed a few more interfaces that I had forgotten --- src/RokuDeploy.spec.ts | 22 +++++++++++++++------- src/RokuDeploy.ts | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index e132b93..82370d6 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -1814,7 +1814,14 @@ describe('index', () => { dest: s`renamed_test.md` }]); - await rokuDeploy.prepublishToStaging(opts as any); + await rokuDeploy.prepublishToStaging({ + rootDir: rootDir, + stagingDir: stagingDir, + files: [ + 'manifest', + 'renamed_test.md' + ] + }); let stagedFilePath = s`${stagingDirValue}/renamed_test.md`; expectPathExists(stagedFilePath); let fileContents = await fsExtra.readFile(stagedFilePath); @@ -1893,11 +1900,12 @@ describe('index', () => { fsExtra.outputFileSync(`${rootDir}/source/main.brs`, ''); await rokuDeploy.prepublishToStaging({ - ...options, + rootDir: rootDir, + stagingDir: stagingDir, files: [ 'source/main.brs' ] - } as any); + }); expectPathExists(s`${stagingDir}/source/main.brs`); expect(count).to.be.greaterThan(4); }); @@ -2073,7 +2081,7 @@ describe('index', () => { writeFiles(rootDir, ['manifest']); - let result = await rokuDeploy.deploy(options as any); + let result = await rokuDeploy.deploy(options); expect(result).not.to.be.undefined; }); @@ -2088,7 +2096,7 @@ describe('index', () => { ...options, //something in the previous test is locking the default output zip file. We should fix that at some point... outDir: s`${tempDir}/test1` - } as any); + }); expect(result).not.to.be.undefined; }); @@ -2097,7 +2105,7 @@ describe('index', () => { options.deleteInstalledChannel = true; mockDoPostRequest(); - await rokuDeploy.deploy(options as any); + await rokuDeploy.deploy(options); expect(spy.called).to.equal(true); }); @@ -2107,7 +2115,7 @@ describe('index', () => { options.deleteInstalledChannel = false; mockDoPostRequest(); - await rokuDeploy.deploy(options as any); + await rokuDeploy.deploy(options); expect(spy.notCalled).to.equal(true); }); diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 97a415f..0de0982 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -1305,6 +1305,7 @@ export interface GetOutputZipFilePathOptions { export interface DeployOptions { deleteInstalledChannel?: boolean; + outDir?: string; } export interface DeployAndSignPackageOptions { From 5da202d56840e5abd529c9a8cb71be6037027c59 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 18:35:29 +0100 Subject: [PATCH 14/30] Attempt to debug github tests --- src/RokuDeploy.spec.ts | 1 - src/RokuDeploy.ts | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 82370d6..557558d 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -1387,7 +1387,6 @@ describe('index', () => { await rokuDeploy.rekeyDevice({ rekeySignedPackage: options.rekeySignedPackage, signingPassword: options.signingPassword, - rootDir: options.rootDir, devId: options.devId }); } catch (e) { diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 0de0982..98aa5c3 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -529,6 +529,7 @@ export class RokuDeploy { if (!path.isAbsolute(options.rekeySignedPackage)) { rekeySignedPackagePath = path.join(options.rootDir, options.rekeySignedPackage); } + console.log(rekeySignedPackagePath, options.rootDir); let requestOptions = this.generateBaseRequestOptions('plugin_inspect', options as any, { mysubmit: 'Rekey', passwd: options.signingPassword, @@ -1279,7 +1280,7 @@ export interface ConvertToSquashfsOptions { export interface RekeyDeviceOptions { rekeySignedPackage: string; signingPassword: string; - rootDir: string; + rootDir?: string; devId: string; } From 58dfebecb134de40d0032d42a3255277235afcf2 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Fri, 17 Nov 2023 18:41:21 +0100 Subject: [PATCH 15/30] Test was fixed on github --- src/RokuDeploy.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 98aa5c3..de604eb 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -529,7 +529,6 @@ export class RokuDeploy { if (!path.isAbsolute(options.rekeySignedPackage)) { rekeySignedPackagePath = path.join(options.rootDir, options.rekeySignedPackage); } - console.log(rekeySignedPackagePath, options.rootDir); let requestOptions = this.generateBaseRequestOptions('plugin_inspect', options as any, { mysubmit: 'Rekey', passwd: options.signingPassword, From fb84132f9ba3db58fa6677a64421713146ca31e0 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Mon, 27 Nov 2023 11:56:29 -0500 Subject: [PATCH 16/30] Fix missing coverage --- src/util.spec.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/util.spec.ts b/src/util.spec.ts index e5ec522..24efcfe 100644 --- a/src/util.spec.ts +++ b/src/util.spec.ts @@ -274,4 +274,13 @@ describe('util', () => { ).to.eql('some-host'); }); }); + + describe('fileExistsCaseInsensitive', () => { + it('detects when a file does not exist inside a dir that does exist', async () => { + fsExtra.ensureDirSync(tempDir); + expect( + await util.fileExistsCaseInsensitive(s`${tempDir}/not-there`) + ).to.be.false; + }); + }); }); From 560da75b2d4703ebebf7a1c321dd4d1990fdfbce Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Mon, 27 Nov 2023 19:32:17 +0100 Subject: [PATCH 17/30] delete retainStagingFolder --- src/RokuDeploy.spec.ts | 18 ------------------ src/RokuDeploy.ts | 4 ---- src/RokuDeployOptions.ts | 7 ------- 3 files changed, 29 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 557558d..bb6ab8e 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -1642,7 +1642,6 @@ describe('index', () => { 'manifest', 'components/!(scenes)/**/*' ], - retainStagingFolder: true, rootDir: rootDir, stagingDir: stagingDir }); @@ -1664,7 +1663,6 @@ describe('index', () => { 'components/**/*', '!components/scenes/**/*' ], - retainStagingFolder: true, rootDir: rootDir, stagingDir: stagingDir }); @@ -1679,7 +1677,6 @@ describe('index', () => { 'manifest', {} ], - retainStagingFolder: true, rootDir: rootDir, stagingDir: stagingDir }); @@ -3363,21 +3360,6 @@ describe('index', () => { ).to.eql(s`${cwd}/staging-folder-path`); }); - it('supports deprecated retainStagingFolder option', () => { - sinon.stub(fsExtra, 'existsSync').callsFake((filePath) => { - return false; - }); - expect( - rokuDeploy.getOptions({ retainStagingFolder: true }).retainStagingDir - ).to.be.true; - expect( - rokuDeploy.getOptions({ retainStagingFolder: true, retainStagingDir: false }).retainStagingDir - ).to.be.false; - expect( - rokuDeploy.getOptions({ retainStagingFolder: true, retainStagingDir: false }).retainStagingFolder - ).to.be.false; - }); - it('calling with no parameters works', () => { sinon.stub(fsExtra, 'existsSync').callsFake((filePath) => { return false; diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index de604eb..59105ed 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -915,9 +915,6 @@ export class RokuDeploy { //fully resolve the folder paths finalOptions.rootDir = path.resolve(process.cwd(), finalOptions.rootDir); finalOptions.outDir = path.resolve(process.cwd(), finalOptions.outDir); - finalOptions.retainStagingDir = (finalOptions.retainStagingDir !== undefined) ? finalOptions.retainStagingDir : finalOptions.retainStagingFolder; - //sync the new option with the old one (for back-compat) - finalOptions.retainStagingFolder = finalOptions.retainStagingDir; let stagingDir = finalOptions.stagingDir || finalOptions.stagingFolderPath; @@ -1235,7 +1232,6 @@ export interface GetDeviceInfoOptions { export interface PrepublishToStagingOptions { files: FileEntry[]; stagingDir?: string; - retainStagingFolder?: boolean; rootDir: string; } diff --git a/src/RokuDeployOptions.ts b/src/RokuDeployOptions.ts index 75e4378..b05a5b4 100644 --- a/src/RokuDeployOptions.ts +++ b/src/RokuDeployOptions.ts @@ -37,13 +37,6 @@ export interface RokuDeployOptions { */ files?: FileEntry[]; - /** - * Set this to true to prevent the staging folder from being deleted after creating the package - * @default false - * @deprecated use `retainStagingDir` instead - */ - retainStagingFolder?: boolean; - /** * Set this to true to prevent the staging folder from being deleted after creating the package * @default false From b15467a9cbd35504e31cf4c29ce4975f6f9f94c0 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Wed, 29 Nov 2023 19:30:43 +0100 Subject: [PATCH 18/30] Remove changing back slashes to forward slashes --- src/RokuDeploy.ts | 18 +----------------- src/util.ts | 24 ------------------------ 2 files changed, 1 insertion(+), 41 deletions(-) diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 59105ed..698ee2e 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -74,23 +74,7 @@ export class RokuDeploy { throw new Error(`Invalid type for "dest" at index ${i} of files array`); } - //objects with src: string - if (typeof entry.src === 'string') { - result.push({ - src: util.standardizePath(entry.src), - dest: util.standardizePath(entry.dest) - }); - - //objects with src:string[] - } else if ('src' in entry && Array.isArray(entry.src)) { - //create a distinct entry for each item in the src array - for (let srcEntry of entry.src) { - result.push({ - src: util.standardizePath(srcEntry), - dest: util.standardizePath(entry.dest) - }); - } - } else { + if (typeof entry.src !== 'string' && !Array.isArray(entry.src)) { throw new Error(`Invalid type for "src" at index ${i} of files array`); } } else { diff --git a/src/util.ts b/src/util.ts index 16aaba4..319877c 100644 --- a/src/util.ts +++ b/src/util.ts @@ -38,30 +38,6 @@ export class Util { } } - /** - * Normalize path and replace all directory separators with current OS separators - * @param thePath - */ - public standardizePath(thePath: string) { - if (!thePath) { - return thePath; - } - return path.normalize( - thePath.replace(/[\/\\]+/g, path.sep) - ); - } - - /** - * Convert all slashes to forward slashes - */ - public toForwardSlashes(thePath: string) { - if (typeof thePath === 'string') { - return thePath.replace(/[\/\\]+/g, '/'); - } else { - return thePath; - } - } - /** * Do a case-insensitive string replacement * @param subject the string that will have its contents replaced From eeabd68f83af618d40f304897758e6a52ff4a6a5 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Mon, 4 Dec 2023 17:05:52 +0100 Subject: [PATCH 19/30] put standardizePath() back --- src/util.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/util.ts b/src/util.ts index da6c0ba..e49eb18 100644 --- a/src/util.ts +++ b/src/util.ts @@ -38,6 +38,19 @@ export class Util { } } + /** + * Normalize path and replace all directory separators with current OS separators + * @param thePath + */ + public standardizePath(thePath: string) { + if (!thePath) { + return thePath; + } + return path.normalize( + thePath.replace(/[\/\\]+/g, path.sep) + ); + } + /** * Do a case-insensitive string replacement * @param subject the string that will have its contents replaced From b89128b8b2ca1c57ff581bf1b51ac2ad530c37ca Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Mon, 4 Dec 2023 17:25:58 +0100 Subject: [PATCH 20/30] Put back more code --- src/RokuDeploy.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 344d19f..38ca6f8 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -74,7 +74,23 @@ export class RokuDeploy { throw new Error(`Invalid type for "dest" at index ${i} of files array`); } - if (typeof entry.src !== 'string' && !Array.isArray(entry.src)) { + //objects with src: string + if (typeof entry.src === 'string') { + result.push({ + src: util.standardizePath(entry.src), + dest: util.standardizePath(entry.dest) + }); + + //objects with src:string[] + } else if ('src' in entry && Array.isArray(entry.src)) { + //create a distinct entry for each item in the src array + for (let srcEntry of entry.src) { + result.push({ + src: util.standardizePath(srcEntry), + dest: util.standardizePath(entry.dest) + }); + } + } else { throw new Error(`Invalid type for "src" at index ${i} of files array`); } } else { From f408c8ac0ec6c8565ef9535cbefe457a9f680e4c Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Mon, 4 Dec 2023 17:37:44 +0100 Subject: [PATCH 21/30] Delete toFrowardSlashes test --- src/util.spec.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/util.spec.ts b/src/util.spec.ts index 8196e65..699d270 100644 --- a/src/util.spec.ts +++ b/src/util.spec.ts @@ -26,17 +26,6 @@ describe('util', () => { }); }); - describe('toForwardSlashes', () => { - it('returns original value for non-strings', () => { - expect(util.toForwardSlashes(undefined)).to.be.undefined; - expect(util.toForwardSlashes(false)).to.be.false; - }); - - it('converts mixed slashes to forward', () => { - expect(util.toForwardSlashes('a\\b/c\\d/e')).to.eql('a/b/c/d/e'); - }); - }); - describe('isChildOfPath', () => { it('works for child path', () => { let parentPath = `${process.cwd()}\\testProject`; From 216054521d0d05d47b2217088aad746d0fb9eacc Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Mon, 4 Dec 2023 17:45:37 +0100 Subject: [PATCH 22/30] No longer force all paths to unix style --- src/util.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/util.ts b/src/util.ts index e49eb18..7e487ec 100644 --- a/src/util.ts +++ b/src/util.ts @@ -129,8 +129,6 @@ export class Util { cwd = cwd.replace(/\\/g, '/'); const globResults = patterns.map(async (pattern) => { - //force all windows-style slashes to unix style - pattern = pattern.replace(/\\/g, '/'); //skip negated patterns (we will use them to filter later on) if (pattern.startsWith('!')) { return pattern; From 8673e633918e8d611fe0973626b070fb1c8dd1ac Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Mon, 4 Dec 2023 14:11:23 -0500 Subject: [PATCH 23/30] Fix windows issues --- src/RokuDeploy.spec.ts | 30 +++++++++++++++--------------- src/RokuDeploy.ts | 4 ++-- src/util.ts | 29 ++++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index f7027c8..1419b2e 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -11,7 +11,7 @@ import * as glob from 'glob'; import type { BeforeZipCallbackInfo } from './RokuDeploy'; import { RokuDeploy } from './RokuDeploy'; import * as errors from './Errors'; -import { util, standardizePath as s } from './util'; +import { util, standardizePath as s, standardizePathPosix as sp } from './util'; import type { FileEntry, RokuDeployOptions } from './RokuDeployOptions'; import { cwd, expectPathExists, expectPathNotExists, expectThrowsAsync, outDir, rootDir, stagingDir, tempDir, writeFiles } from './testUtils.spec'; import { createSandbox } from 'sinon'; @@ -1722,7 +1722,7 @@ describe('index', () => { await rokuDeploy.prepublishToStaging({ files: [ { - src: `${rootDir}/manifest`, + src: sp`${rootDir}/manifest`, dest: '' }, { @@ -2093,7 +2093,7 @@ describe('index', () => { src: `long/source/path`, dest: `long/dest/path` }])).to.eql([{ - src: s`long/source/path`, + src: sp`long/source/path`, dest: s`long/dest/path` }]); }); @@ -2151,7 +2151,7 @@ describe('index', () => { src: 'manifest', dest: undefined }, { - src: s`source/main.brs`, + src: sp`source/main.brs`, dest: undefined }]); }); @@ -2163,7 +2163,7 @@ describe('index', () => { dest: 'source/config.brs' } ])).to.eql([{ - src: s`source/config.dev.brs`, + src: sp`source/config.dev.brs`, dest: s`source/config.brs` }]); }); @@ -2651,7 +2651,7 @@ describe('index', () => { describe('getFilePaths', () => { const otherProjectName = 'otherProject'; - const otherProjectDir = s`${rootDir}/../${otherProjectName}`; + const otherProjectDir = sp`${rootDir}/../${otherProjectName}`; //create baseline project structure beforeEach(() => { fsExtra.ensureDirSync(`${rootDir}/components/emptyFolder`); @@ -3139,7 +3139,7 @@ describe('index', () => { //dest not specified expect(await rokuDeploy.getFilePaths([{ - src: s`${cwd}/README.md` + src: sp`${cwd}/README.md` }], options.rootDir)).to.eql([{ src: s`${cwd}/README.md`, dest: s`README.md` @@ -3147,7 +3147,7 @@ describe('index', () => { //dest specified expect(await rokuDeploy.getFilePaths([{ - src: path.join(cwd, 'README.md'), + src: sp`${cwd}/README.md`, dest: 'docs/README.md' }], options.rootDir)).to.eql([{ src: s`${cwd}/README.md`, @@ -3157,7 +3157,7 @@ describe('index', () => { let paths: any[]; paths = await rokuDeploy.getFilePaths([{ - src: s`${cwd}/README.md`, + src: sp`${cwd}/README.md`, dest: s`docs/README.md` }], outDir); @@ -3169,7 +3169,7 @@ describe('index', () => { //top-level string paths pointing to files outside the root should thrown an exception await expectThrowsAsync(async () => { paths = await rokuDeploy.getFilePaths([ - s`${cwd}/README.md` + sp`${cwd}/README.md` ], outDir); }); }); @@ -3180,7 +3180,7 @@ describe('index', () => { ]); expect( await rokuDeploy.getFilePaths([{ - src: path.join('..', 'README.md') + src: sp`../README.md` }], rootDir) ).to.eql([{ src: s`${rootDir}/../README.md`, @@ -3189,7 +3189,7 @@ describe('index', () => { expect( await rokuDeploy.getFilePaths([{ - src: path.join('..', 'README.md'), + src: sp`../README.md`, dest: 'docs/README.md' }], rootDir) ).to.eql([{ @@ -3204,17 +3204,17 @@ describe('index', () => { ]); await expectThrowsAsync( rokuDeploy.getFilePaths([ - path.join('..', 'README.md') + path.posix.join('..', 'README.md') ], outDir) ); }); it('supports overriding paths', async () => { let paths = await rokuDeploy.getFilePaths([{ - src: s`${rootDir}/components/component1.brs`, + src: sp`${rootDir}/components/component1.brs`, dest: 'comp1.brs' }, { - src: s`${rootDir}/components/screen1/screen1.brs`, + src: sp`${rootDir}/components/screen1/screen1.brs`, dest: 'comp1.brs' }], rootDir); expect(paths).to.be.lengthOf(1); diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 38ca6f8..37762ce 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -77,7 +77,7 @@ export class RokuDeploy { //objects with src: string if (typeof entry.src === 'string') { result.push({ - src: util.standardizePath(entry.src), + src: entry.src, dest: util.standardizePath(entry.dest) }); @@ -86,7 +86,7 @@ export class RokuDeploy { //create a distinct entry for each item in the src array for (let srcEntry of entry.src) { result.push({ - src: util.standardizePath(srcEntry), + src: srcEntry, dest: util.standardizePath(entry.dest) }); } diff --git a/src/util.ts b/src/util.ts index 7e487ec..cb90917 100644 --- a/src/util.ts +++ b/src/util.ts @@ -46,11 +46,21 @@ export class Util { if (!thePath) { return thePath; } - return path.normalize( - thePath.replace(/[\/\\]+/g, path.sep) - ); + return path.normalize(thePath).replace(/[\/\\]+/g, path.sep); } + /** + * Normalize path and replace all directory separators with current OS separators + * @param thePath + */ + public standardizePathPosix(thePath: string) { + if (!thePath) { + return thePath; + } + return path.normalize(thePath).replace(/[\/\\]+/g, '/'); + } + + /** * Do a case-insensitive string replacement * @param subject the string that will have its contents replaced @@ -232,3 +242,16 @@ export function standardizePath(stringParts, ...expressions: any[]) { result.join('') ); } + +/** + * A tagged template literal function for standardizing the path and making all path separators forward slashes + */ +export function standardizePathPosix(stringParts, ...expressions: any[]) { + let result = []; + for (let i = 0; i < stringParts.length; i++) { + result.push(stringParts[i], expressions[i]); + } + return util.standardizePathPosix( + result.join('') + ); +} From 95d9905666f7727f8d49a2ae48567018cda06c3f Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Mon, 4 Dec 2023 14:19:30 -0500 Subject: [PATCH 24/30] fix coverage failure --- src/util.spec.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/util.spec.ts b/src/util.spec.ts index 699d270..b174570 100644 --- a/src/util.spec.ts +++ b/src/util.spec.ts @@ -26,6 +26,19 @@ describe('util', () => { }); }); + describe('standardizePathPosix', () => { + it('returns falsey value back unchanged', () => { + expect(util.standardizePathPosix(null)).to.eql(null); + expect(util.standardizePathPosix(undefined)).to.eql(undefined); + expect(util.standardizePathPosix(false as any)).to.eql(false); + expect(util.standardizePathPosix(0 as any)).to.eql(0); + }); + + it('always returns forward slashes', () => { + expect(util.standardizePathPosix('C:\\projects/some\\folder')).to.eql('C:/projects/some/folder'); + }); + }); + describe('isChildOfPath', () => { it('works for child path', () => { let parentPath = `${process.cwd()}\\testProject`; From 787ea0e570ceb4685a2bdfae7446a95023caf87e Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Wed, 13 Dec 2023 10:46:17 -0500 Subject: [PATCH 25/30] Edit readme --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 42bcc26..7d34747 100644 --- a/README.md +++ b/README.md @@ -256,8 +256,7 @@ The object structure is as follows: } ``` #### { src; dest } Object Rules - - if `src` is a non-glob path to a single file, then `dest` should include the filename and extension. For example: - `{ src: "lib/Promise/promise.brs", dest: "source/promise.brs"}` + - if `src` is required to follow glob style (i.e. forward-slashes only). You can learn more [here](https://www.npmjs.com/package/fast-glob?activeTab=readme#how-to-write-patterns-on-windows). - if `src` is a glob pattern, then `dest` should be a path to the folder in the output directory. For example: `{ src: "lib/*.brs", dest: "source/lib"}` @@ -326,7 +325,7 @@ Here are the available options. The defaults are shown to the right of the optio "manifest" ] ``` - An array of file paths, globs, or {src:string;dest:string} objects that will be copied into the deployment package. + An array of file paths, globs, or {src:string;dest:string} objects that will be copied into the deployment package. This is required to use glob style. You can learn more [here](https://www.npmjs.com/package/fast-glob?activeTab=readme#how-to-write-patterns-on-windows). Using the {src;dest} objects will allow you to move files into different destination paths in the deployment package. This would be useful for copying environment-specific configs into a common config location From 22957cab4266c88acbb2e55e922c7846d85d9b63 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Thu, 14 Dec 2023 12:49:01 -0500 Subject: [PATCH 26/30] Add tests to check for escaped and unescaped glob patterns --- src/RokuDeploy.spec.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 1419b2e..59de183 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -2817,6 +2817,36 @@ describe('index', () => { }]); }); + it('Find files in folder using asterisk glob pattern', async () => { + fsExtra.outputFileSync(`${rootDir}/*est/file.brs`, ''); + fsExtra.outputFileSync(`${rootDir}/test/file.brs`, ''); + expect(await getFilePaths([ + '*est/*' + ], + rootDir + )).to.eql([{ + src: s`${rootDir}/*est/file.brs`, + dest: '*est/file.brs' + }, + { + src: s`${rootDir}/test/file.brs`, + dest: 'test/file.brs' + }]); + }); + + it('Finds files in folder with escaped asterisk glob pattern', async () => { + fsExtra.outputFileSync(`${rootDir}/*est/file.brs`, ''); + fsExtra.outputFileSync(`${rootDir}/test/file.brs`, ''); + expect(await getFilePaths([ + '\\*est/*' + ], + rootDir + )).to.eql([{ + src: s`${rootDir}/*est/file.brs`, + dest: '*est/file.brs' + }]); + }); + it('throws exception when top-level strings reference files not under rootDir', async () => { writeFiles(otherProjectDir, [ 'manifest' From b11be3674375bd5ea7cfd743b52298d443e358e3 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Thu, 14 Dec 2023 16:11:01 -0500 Subject: [PATCH 27/30] Update README.md Co-authored-by: Bronley Plumb --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d34747..809d966 100644 --- a/README.md +++ b/README.md @@ -256,7 +256,7 @@ The object structure is as follows: } ``` #### { src; dest } Object Rules - - if `src` is required to follow glob style (i.e. forward-slashes only). You can learn more [here](https://www.npmjs.com/package/fast-glob?activeTab=readme#how-to-write-patterns-on-windows). +- if `src` is a non-glob path to a single file, then `dest` should include the filename and extension. For example: - if `src` is a glob pattern, then `dest` should be a path to the folder in the output directory. For example: `{ src: "lib/*.brs", dest: "source/lib"}` From bfcedbb1ae36763b224cf7455853b04fa9bc80c6 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Thu, 14 Dec 2023 16:11:20 -0500 Subject: [PATCH 28/30] Update README.md Co-authored-by: Bronley Plumb --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 809d966..4dd3a33 100644 --- a/README.md +++ b/README.md @@ -325,7 +325,7 @@ Here are the available options. The defaults are shown to the right of the optio "manifest" ] ``` - An array of file paths, globs, or {src:string;dest:string} objects that will be copied into the deployment package. This is required to use glob style. You can learn more [here](https://www.npmjs.com/package/fast-glob?activeTab=readme#how-to-write-patterns-on-windows). + An array of file paths, globs, or `{ src: string; dest: string }` objects that will be copied into the deployment package. Make sure to _exclusively_ use forward slashes ( `/` ) for path separators (even on Windows), as backslashes are reserved for character escaping. You can learn more about this requirement [here](https://www.npmjs.com/package/fast-glob?activeTab=readme#how-to-write-patterns-on-windows). Using the {src;dest} objects will allow you to move files into different destination paths in the deployment package. This would be useful for copying environment-specific configs into a common config location From 565c0961149fbef909bcfbfa25f7d7c0c81fffcd Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Thu, 14 Dec 2023 16:13:08 -0500 Subject: [PATCH 29/30] change tests to accomodate windows machines --- src/RokuDeploy.spec.ts | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 59de183..8e0d788 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -2817,33 +2817,28 @@ describe('index', () => { }]); }); - it('Find files in folder using asterisk glob pattern', async () => { - fsExtra.outputFileSync(`${rootDir}/*est/file.brs`, ''); - fsExtra.outputFileSync(`${rootDir}/test/file.brs`, ''); + it('Finds folder using square brackets glob pattern', async () => { + fsExtra.outputFileSync(`${rootDir}/e/file.brs`, ''); expect(await getFilePaths([ - '*est/*' + '[test]/*' ], rootDir )).to.eql([{ - src: s`${rootDir}/*est/file.brs`, - dest: '*est/file.brs' - }, - { - src: s`${rootDir}/test/file.brs`, - dest: 'test/file.brs' + src: s`${rootDir}/e/file.brs`, + dest: 'e/file.brs' }]); }); - it('Finds files in folder with escaped asterisk glob pattern', async () => { - fsExtra.outputFileSync(`${rootDir}/*est/file.brs`, ''); - fsExtra.outputFileSync(`${rootDir}/test/file.brs`, ''); + it('Finds folder with escaped square brackets glob pattern as name', async () => { + fsExtra.outputFileSync(`${rootDir}/[test]/file.brs`, ''); + fsExtra.outputFileSync(`${rootDir}/e/file.brs`, ''); expect(await getFilePaths([ - '\\*est/*' + '\\[test\\]/*' ], rootDir )).to.eql([{ - src: s`${rootDir}/*est/file.brs`, - dest: '*est/file.brs' + src: s`${rootDir}/[test]/file.brs`, + dest: '[test]/file.brs' }]); }); From 0e785241cd3ca3263c412107039f53e4d2bfdfe2 Mon Sep 17 00:00:00 2001 From: Milap Naik Date: Thu, 14 Dec 2023 16:20:12 -0500 Subject: [PATCH 30/30] Process slashes properly --- src/RokuDeploy.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 8e0d788..c090fd4 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -2825,7 +2825,7 @@ describe('index', () => { rootDir )).to.eql([{ src: s`${rootDir}/e/file.brs`, - dest: 'e/file.brs' + dest: s`e/file.brs` }]); }); @@ -2838,7 +2838,7 @@ describe('index', () => { rootDir )).to.eql([{ src: s`${rootDir}/[test]/file.brs`, - dest: '[test]/file.brs' + dest: s`[test]/file.brs` }]); });