Giter Site home page Giter Site logo

roku-deploy's People

Contributors

chrisdp avatar christian-holbrook avatar dependabot[bot] avatar elliot-nelson avatar fumer-fubotv avatar georgejecook avatar greenkeeper[bot] avatar leightyb-teachco avatar sebwojtasik avatar triwav avatar twitchbronbron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

roku-deploy's Issues

rokuDeploy is not a function

Error: TypeError: rokuDeploy is not a function

Code:

const rokuDeploy = require('roku-deploy');
const configs = require('../rokudeploy.json');


rokuDeploy(configs)
  .then(() => console.log('deployed'))
  .catch((e) => console.log(e));

Note that npm run deploy runs with no errors with package.json:

  "scripts": {
    "deploy": "roku-deploy"
  }

Bug with {src;dest} object handling

I would expect these two patterns to be equivalent:

"components/*",
{ src: "components/*" }

According to the documentation, for {src;dest;} objects, when dest is omitted, the root of the output folder is assumed. However, the current implementation (v3.5.3) does not work that way.

Consider the file components/CustomButton.brs.

  • "components/*" results in pkg:/components/CustomButton.brs. (as expected)
  • {src: "components/*" } results in pkg:/CustomButton.brs (unexpected)

This should be corrected so that the src;dest pattern works the same as the raw string approach. However, this would be a breaking change, so we need to consider that.

Roku deploy with args

Allow options (perhaps in bsconfig.json) to specify args passed when launching, things like mediaType and contentId
To allow launching with deep link data directly.
It would be nice that brighterscript require('brighterscript').ProgramBuilder can take these launch arguments and pass them to the app on Roku.

Make deleting the previously installed channel optional

Just wanted to add an option to not delete the previously installed channel upon publishing as sometimes it proves to be unneccesary and delete local storage files associated with the channel and can slow down iteration time.

ESOCKETTIMEDOUT at deploy

I get ESOCKETTIMEDOUT error at every attempt via roku-deploy for a simple project, but uploading roku-deploy.zip via Roku web server works

Log:

npm run deploy

> [email protected] deploy
> roku-deploy

Error: ESOCKETTIMEDOUT
    at ClientRequest.<anonymous> (C:\Users\DeKaN\IdeaProjects\roku-sdk\composer\node_modules\request\request.js:816:19)
    at Object.onceWrapper (node:events:509:28)
    at ClientRequest.emit (node:events:390:28)
    at Socket.emitRequestTimeout (node:_http_client:763:9)
    at Object.onceWrapper (node:events:509:28)
    at Socket.emit (node:events:402:35)
    at Socket._onTimeout (node:net:486:8)
    at listOnTimeout (node:internal/timers:557:17)
    at processTimers (node:internal/timers:500:7) {
  code: 'ESOCKETTIMEDOUT',
  connect: false
}

package.json's scripts:

  "scripts": {
    "build": "bsc",
    "deploy": "roku-deploy",
    "lint": "bslint --project ./bsconfig.json",
    "package": "bsc --create-package",
    "validate": "bsc --create-package=false --copy-to-staging=false"
  }

rokudeploy.json:

{
    "rootDir": "dist",
    "remoteDebug": true,
    "logLevel": "debug",
    "host": "192.168.1.22",
    "password": "123456"
}

bsconfig.json:

// https://github.com/rokucommunity/brighterscript brighterscript config
{
  "rootDir": "src",
  "files": [
    "manifest",
    "source/**/*.*",
    "components/**/*.*",
    "images/**/*.*"
  ],
  "plugins": ["@rokucommunity/bslint"],
  "stagingFolderPath": "dist",
  "retainStagingFolder": true,
  "autoImportComponentScript": true,
  "sourceMap": true,
  "debug": {
		"enableDebugProtocol": true
	}
}

Update files array defaults

The default value for the files array was created a long time ago, and there are a few enhancements I think we should make.

Here's my proposal for the updated files array.

{
    "files": [
        //current files array
        "source/**/*.*",
        "components/**/*.*",
        "images/**/*.*:",
        "manifest",

        //new entries

        "locale/**/*",
        "fonts/**/*",

        //exclude root-level node_modules folder
        "!node_modules",
        //exclude markdown files, mac and windows fs database files
        "!**/*.{md,DS_Store,db}",
    ]
}

Is there anything else I'm missing?

Better error message for src;dest

Could we have better error messages for certain types of invalid src;dest objects? For example:

src is file and dest is dir

`` { src: "../manifest", dest: "./"}``` This one should be easy to detect. We could run src` through the `glob.hasMagic` method, and if it's not a magic string, check for `fsExtra.isFile` or `fsExtra.isDir`. Then, we know for sure that the path on the right needs to be a path to a file, or if referencing a dir, throw an error saying directories can't be referenced directly.

Throw better errors

Throw better errors / or successes with better details. Use cases where we don’t return a value (We should be able to return the actual response (and everything else) for external code to process)

This is probably a breaking change.

Add device rekeying functionality

Example rekeying function in js:

module.exports.rekey = function(target, devPass, pkgPass, rekeyPath, timeout, callback) {
  var url = `http://${target}/plugin_inspect`;                                  
  var auth = {                                                                  
    user: 'rokudev',                                                            
    pass: devPass,                                                              
    sendImmediately: false                                                      
  };                                                                            
  var data = {                                                                  
    mysubmit: 'Rekey',                                                          
    passwd: pkgPass,                                                            
    archive: fs.createReadStream(rekeyPath)                                     
  };                                                                            
  console.log()                                                                 
  console.log(`Rekeying ${target} from ${rekeyPath}`);                          
  console.log()                                                                 
  request.post({url: url, auth: auth, formData: data, timeout: timeout}, (err, response, body) => {
    if (checkNetworkError(err, response) === false) {                           
      if (body.match(/<font color="red">Success.<\/font>/) === null) {          
        /* If some other failure, such as out of space, report it here */       
        let errorMessages = body.match(/<font color="red">([^<]*)/);            
        if (errorMessages !== null) {                                           
          errorMessages.shift()                                                 
          errorMessages.forEach((message) => {                                  
            console.log(`Device install error: ${message}`);                    
          });                                                                   
        }                                                                       
        else {                                                                  
          console.log("Rekey failed");                                          
        }                                                                       
      }                                                                         
      else {                                                                    
        console.log("Rekey succeeded");                                         
      }                                                                         
      callback();                                                               
    }                                                                           
    else {                                                                      
      callback(err);                                                            
    }                                                                           
  });                                                                           
}        

Support including files located outside of rootDir

Currently the files array only supports files found within rootDir. It would be useful to support files found outside of the root dir, whether it be via an absolute file path or a relative path that uses .. to walk backwards. So something like this:

"files": [
    "manifest",
    "source/**/*.*",
    "C:/projects/common/lib.brs"
]

Would copy lib.brs to the root of the outDir.

You could also do this:

"files": [
    "manifest",
    "source/**/*.*",
    {
        "src": "C:/projects/common/lib.brs",
        "dest": "common"
    }
}

Would copy lib.brs to outDir/common/lib.brs.

You could also do this:

"files": [
    "manifest",
    "source/**/*.*",
    {
        "src": "../common/lib.brs",
        "dest": "common"
    }
}

Would copy lib.brs to outDir/common/lib.brs.

roku deploy crashes the roku device

When running roku deploy the following things happen

  1. The app deploys successfully
  2. The app shows the launch screen
  3. The app freezes at the launch screen
  4. Roku device crashes
  5. When the device reboots the app is installed and working.

I can repeat this for the samples project https://github.com/rokudev/samples/tree/master/getting%20started/SceneGraphTutorial

Simply add in the required information and either create a node script or create a file calling these methods. Both result in the same issue when running deploy.

rokudeploy.json

"host": "192.168.1.14", // your device IP
"password": "test" // your device password

Is there anything I'm missing?

Output message after successful deployment:

{
  message: 'Successful deploy',
  results: {
    response: IncomingMessage {
      _readableState: [ReadableState],
      readable: false,
      _events: [Object: null prototype],
      _eventsCount: 4,
      _maxListeners: undefined,
      socket: [Socket],
      connection: [Socket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      headers: [Object],
      rawHeaders: [Array],
      trailers: {},
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 200,
      statusMessage: 'OK',
      client: [Socket],
      _consuming: true,
      _dumped: false,
      req: [ClientRequest],
      request: [Request],
      toJSON: [Function: responseToJSON],
      caseless: [Caseless],
      body: '<html>\n' +
        '<head>\n' +
        '  <meta charset="utf-8">\n' +
        '  <meta name="HandheldFriendly" content="True">\n' +
        '  <title> Roku Development Kit </title>\n' +
        '\n' +
        '  <link rel="stylesheet" type="text/css" media="screen" href="css/global.css" />\n' +
        '</head>\n' +
        '<body>\n' +
        '  <div id="root" style="background: #fff">\n' +
        '  \n' +
        '  \n' +
        '  </div>\n' +
        '\n' +
        '  <!-- Keep it, so old scripts can continue to work -->\n' +
        '  <div style="display:none">\n' +
        '    <font color="red">Application Received: 794759 bytes stored.\n' +
        '</font>\n' +
        '    <font color="red">Install Success.</font>\n' +
        '    <p><font face="Courier">16af54a339fa3051f2b248c15d3d4d09 <br /> zip file in internal memory (794759 bytes)</font></p>\n' +
        '  </div>\n' +
        '\n' +
        '  <script type="text/javascript" src="css/global.js"></script>\n' +
        '  <script type="text/javascript">\n' +
        '  \n' +
        '      // Include core components and resounce bundle (needed)\n' +
        '      Shell.resource.set(null, {\n' +
        '          endpoints: {} \n' +
        '      });\n' +
        "      Shell.create('Roku.Event.Key');\n" +
        "      Shell.create('Roku.Events.Resize');\n" +
        "      Shell.create('Roku.Events.Scroll');  \n" +
        '\n' +
        '      // Create global navigation and render it\n' +
        "      var nav = Shell.create('Roku.Nav')\n" +
        "        .trigger('Enable standalone and utility mode - hide user menu, shopping cart, and etc.')\n" +
        "        .trigger('Use compact footer')\n" +
        "        .trigger('Hide footer')\n" +
        "        .trigger('Render', document.getElementById('root'))\n" +
        '        // Create custom links\n' +
        "        .trigger('Remove all feature links from header')\n" +
        "        .trigger('Add feature link in header', {\n" +
        "            text: 'Installer',\n" +
        "            url: 'plugin_install'\n" +
        '        })\n' +
        "        .trigger('Add feature link in header', {\n" +
        "            text: 'Utilities',\n" +
        "            url: 'plugin_inspect'\n" +
        '        })\n' +
        '        \n' +
        "        .trigger('Add feature link in header', { text: 'Packager (no dev key)' });\n" +
        '\n' +
        '      // Retrieve main content body node\n' +
        "      var node = nav.invoke('Get main body section mounting node');\n" +
        '      \n' +
        '      // Create page container and page header\n' +
        "      var container = Shell.create('Roku.Nav.Page.Standard').trigger('Render', node);\n" +
        "      node = container.invoke('Get main body node');\n" +
        "      container.invoke('Get headline node').innerHTML = 'Development Application Installer';\n" +
        '\n' +
        `      node.innerHTML = '<p>Currently Installed Application:</p><p><font face="Courier">16af54a339fa3051f2b248c15d3d4d09 <br /> zip file in internal memory (794759 bytes)</font></p>';\n` +
        '\n' +
        '      // Set up form in main body content area\n' +
        "      form = Shell.create('Roku.Form')\n" +
        "        .trigger('Set form action URL', 'plugin_install')\n" +
        "        .trigger('Set form encryption type to multi-part')\n" +
        '        .trigger("Add file upload button", { \n' +
        '            name: "archive",\n' +
        '            label: "File:" \n' +
        '         })\n' +
        '        .trigger("Add hidden input field", {\n' +
        '            name: "mysubmit"\n' +
        '      });\n' +
        '\n' +
        '      // Render some buttons\n' +
        "      var Delete = document.createElement('BUTTON');\n" +
        "      Delete.className = 'roku-button';\n" +
        "      Delete.innerHTML = 'Delete';\n" +
        '      Delete.onclick = function() {\n' +
        "          form.trigger('Update input field value', { name: 'mysubmit', value: 'Delete'})\n" +
        "          form.trigger('Force submit');   \n" +
        '      };\n' +
        '      node.appendChild(Delete);\n' +
        '      \n' +
        '      if (true)\n' +
        '      {\n' +
        '        // Render some buttons\n' +
        "        var convert = document.createElement('BUTTON');\n" +
        "        convert.className = 'roku-button';\n" +
        "        convert.innerHTML = 'Convert to cramfs';\n" +
        '        convert.onclick = function() {\n' +
        "            form.trigger('Update input field value', { name: 'mysubmit', value: 'Convert to cramfs'})\n" +
        "            form.trigger('Force submit');   \n" +
        '        };\n' +
        '        node.appendChild(convert);\n' +
        '\n' +
        "        var convert2 = document.createElement('BUTTON');\n" +
        "        convert2.className = 'roku-button';\n" +
        "        convert2.innerHTML = 'Convert to squashfs';\n" +
        '        convert2.onclick = function() {\n' +
        "            form.trigger('Update input field value', { name: 'mysubmit', value: 'Convert to squashfs'})\n" +
        "            form.trigger('Force submit');   \n" +
        '        };\n' +
        '        node.appendChild(convert2);\n' +
        '      }\n' +
        '      \n' +
        "      var hrDiv = document.createElement('div');\n" +
        "      hrDiv.innerHTML = '<hr />';\n" +
        '      node.appendChild(hrDiv);\n' +
        '\n' +
        "      form.trigger('Render', node);\n" +
        '\n' +
        '      // Render some buttons\n' +
        "      var submit = document.createElement('BUTTON');\n" +
        "      submit.className = 'roku-button';\n" +
        "      submit.innerHTML = 'Replace';\n" +
        '      submit.onclick = function() {\n' +
        "          form.trigger('Update input field value', { name: 'mysubmit', value: 'replace'})\n" +
        "          if(form.invoke('Validate and get input values').valid === true) {\n" +
        "            form.trigger('Force submit');   \n" +
        '          }\n' +
        '      };\n' +
        '      node.appendChild(submit);\n' +
        '\n' +
        "      var d = document.createElement('div');\n" +
        "      d.innerHTML = '<br />';\n" +
        '      node.appendChild(d);\n' +
        '\n' +
        '      // Reder messages (info, error, and success)\n' +
        "      Shell.create('Roku.Message').trigger('Set message type', 'success').trigger('Set message content', 'Application Received: 794759 bytes stored.').trigger('Render', node);\n" +
        '      \n' +
        "      Shell.create('Roku.Message').trigger('Set message type', 'success').trigger('Set message content', 'Install Success.').trigger('Render', node);\n" +
        '\n' +
        '  </script>\n' +
        '\n' +
        '</body>\n' +
        '</html>\n',
      [Symbol(kCapture)]: false
    },
    body: '<html>\n' +
      '<head>\n' +
      '  <meta charset="utf-8">\n' +
      '  <meta name="HandheldFriendly" content="True">\n' +
      '  <title> Roku Development Kit </title>\n' +
      '\n' +
      '  <link rel="stylesheet" type="text/css" media="screen" href="css/global.css" />\n' +
      '</head>\n' +
      '<body>\n' +
      '  <div id="root" style="background: #fff">\n' +
      '  \n' +
      '  \n' +
      '  </div>\n' +
      '\n' +
      '  <!-- Keep it, so old scripts can continue to work -->\n' +
      '  <div style="display:none">\n' +
      '    <font color="red">Application Received: 794759 bytes stored.\n' +
      '</font>\n' +
      '    <font color="red">Install Success.</font>\n' +
      '    <p><font face="Courier">16af54a339fa3051f2b248c15d3d4d09 <br /> zip file in internal memory (794759 bytes)</font></p>\n' +
      '  </div>\n' +
      '\n' +
      '  <script type="text/javascript" src="css/global.js"></script>\n' +
      '  <script type="text/javascript">\n' +
      '  \n' +
      '      // Include core components and resounce bundle (needed)\n' +
      '      Shell.resource.set(null, {\n' +
      '          endpoints: {} \n' +
      '      });\n' +
      "      Shell.create('Roku.Event.Key');\n" +
      "      Shell.create('Roku.Events.Resize');\n" +
      "      Shell.create('Roku.Events.Scroll');  \n" +
      '\n' +
      '      // Create global navigation and render it\n' +
      "      var nav = Shell.create('Roku.Nav')\n" +
      "        .trigger('Enable standalone and utility mode - hide user menu, shopping cart, and etc.')\n" +
      "        .trigger('Use compact footer')\n" +
      "        .trigger('Hide footer')\n" +
      "        .trigger('Render', document.getElementById('root'))\n" +
      '        // Create custom links\n' +
      "        .trigger('Remove all feature links from header')\n" +
      "        .trigger('Add feature link in header', {\n" +
      "            text: 'Installer',\n" +
      "            url: 'plugin_install'\n" +
      '        })\n' +
      "        .trigger('Add feature link in header', {\n" +
      "            text: 'Utilities',\n" +
      "            url: 'plugin_inspect'\n" +
      '        })\n' +
      '        \n' +
      "        .trigger('Add feature link in header', { text: 'Packager (no dev key)' });\n" +
      '\n' +
      '      // Retrieve main content body node\n' +
      "      var node = nav.invoke('Get main body section mounting node');\n" +
      '      \n' +
      '      // Create page container and page header\n' +
      "      var container = Shell.create('Roku.Nav.Page.Standard').trigger('Render', node);\n" +
      "      node = container.invoke('Get main body node');\n" +
      "      container.invoke('Get headline node').innerHTML = 'Development Application Installer';\n" +
      '\n' +
      `      node.innerHTML = '<p>Currently Installed Application:</p><p><font face="Courier">16af54a339fa3051f2b248c15d3d4d09 <br /> zip file in internal memory (794759 bytes)</font></p>';\n` +
      '\n' +
      '      // Set up form in main body content area\n' +
      "      form = Shell.create('Roku.Form')\n" +
      "        .trigger('Set form action URL', 'plugin_install')\n" +
      "        .trigger('Set form encryption type to multi-part')\n" +
      '        .trigger("Add file upload button", { \n' +
      '            name: "archive",\n' +
      '            label: "File:" \n' +
      '         })\n' +
      '        .trigger("Add hidden input field", {\n' +
      '            name: "mysubmit"\n' +
      '      });\n' +
      '\n' +
      '      // Render some buttons\n' +
      "      var Delete = document.createElement('BUTTON');\n" +
      "      Delete.className = 'roku-button';\n" +
      "      Delete.innerHTML = 'Delete';\n" +
      '      Delete.onclick = function() {\n' +
      "          form.trigger('Update input field value', { name: 'mysubmit', value: 'Delete'})\n" +
      "          form.trigger('Force submit');   \n" +
      '      };\n' +
      '      node.appendChild(Delete);\n' +
      '      \n' +
      '      if (true)\n' +
      '      {\n' +
      '        // Render some buttons\n' +
      "        var convert = document.createElement('BUTTON');\n" +
      "        convert.className = 'roku-button';\n" +
      "        convert.innerHTML = 'Convert to cramfs';\n" +
      '        convert.onclick = function() {\n' +
      "            form.trigger('Update input field value', { name: 'mysubmit', value: 'Convert to cramfs'})\n" +
      "            form.trigger('Force submit');   \n" +
      '        };\n' +
      '        node.appendChild(convert);\n' +
      '\n' +
      "        var convert2 = document.createElement('BUTTON');\n" +
      "        convert2.className = 'roku-button';\n" +
      "        convert2.innerHTML = 'Convert to squashfs';\n" +
      '        convert2.onclick = function() {\n' +
      "            form.trigger('Update input field value', { name: 'mysubmit', value: 'Convert to squashfs'})\n" +
      "            form.trigger('Force submit');   \n" +
      '        };\n' +
      '        node.appendChild(convert2);\n' +
      '      }\n' +
      '      \n' +
      "      var hrDiv = document.createElement('div');\n" +
      "      hrDiv.innerHTML = '<hr />';\n" +
      '      node.appendChild(hrDiv);\n' +
      '\n' +
      "      form.trigger('Render', node);\n" +
      '\n' +
      '      // Render some buttons\n' +
      "      var submit = document.createElement('BUTTON');\n" +
      "      submit.className = 'roku-button';\n" +
      "      submit.innerHTML = 'Replace';\n" +
      '      submit.onclick = function() {\n' +
      "          form.trigger('Update input field value', { name: 'mysubmit', value: 'replace'})\n" +
      "          if(form.invoke('Validate and get input values').valid === true) {\n" +
      "            form.trigger('Force submit');   \n" +
      '          }\n' +
      '      };\n' +
      '      node.appendChild(submit);\n' +
      '\n' +
      "      var d = document.createElement('div');\n" +
      "      d.innerHTML = '<br />';\n" +
      '      node.appendChild(d);\n' +
      '\n' +
      '      // Reder messages (info, error, and success)\n' +
      "      Shell.create('Roku.Message').trigger('Set message type', 'success').trigger('Set message content', 'Application Received: 794759 bytes stored.').trigger('Render', node);\n" +
      '      \n' +
      "      Shell.create('Roku.Message').trigger('Set message type', 'success').trigger('Set message content', 'Install Success.').trigger('Render', node);\n" +
      '\n' +
      '  </script>\n' +
      '\n' +
      '</body>\n' +
      '</html>\n'
  }
}

enhanced logging levels

It would be nice to have multiple levels of logging in roku-deploy to help debug issues when they arise. Here are the following tasks necessary to complete this:

  • add new option to RokuDeployOptions called logLevel with the following signature:
    logLevel: 'error' | 'warn' | 'log' | 'info' | 'debug' | 'trace'

  • logLevel should be supported in the following scenarios:

    • passed in as --log-level from the command line (see this section in brighterscript for how to parse from the command line).
    • passed in the options: RokuDeployOptions anywhere in roku-deploy
    • loded from roku-deploy.json
    • loaded from bsconfig.json
  • use @rokucommunity/logger package in this project, and make it an instance variable on the RokuDeploy class so it can be mocked or swapped out during tests or other situations.

  • convert any current console.* calls in roku-deploy to use this.logger.*.

  • add additional logging calls as needed

Add proper docs for full usage

We need proper documentation for:

  • how to use the new CLI
  • how to use the programmatic APIs
  • migration guide from v3 to v4

Much better responses from the various functions

Sometimes roku-deploy just returns a string as the response from doing something. That's not overly helpful .We should do a much better job return a structured response/status object so the callers can make more informed decisions about this stuff.

Problems to solve:

  • roku has info, warn, error stuff. we're not logging those. we should. So if we're gonna throw, we should log better reasons why.
  • our tools like vscode are likely not taking advantage of this when it could. we're just looking at "it threw" and logging it. We should try passing along info, warn, error stuff to the console.

We might need to append rokuMessages to every error.

interface RokuDeployError {
    message: string;
    stack: any;
    rokuMessages: RokuMessages;
}

Use unix paths internally

To simplify logic (globs, string replacements, etc...) we should force all incoming paths to use forward slashes. Then, only on the way out would we replace them with the os-specific path separator. This would help slightly with performance, and also simplify our internal logic.

roku-deploy does not respect bsconfig.json

My bsconfig.json looks like this

{
    "extends": "config/bsconfig.base.json",
   ...
}

But roku deploy does not seem to read from config/bsconfig.base.json

Making this fails (because it's looking in the wrong staging folder)

rokuDeploy.zipPackage({
    outDir: '.',
    outFile: zip_name
}).then(function(){
    console.log(`${zip_name} created`)
}, function(error) {
    console.error(error);
});

Upgrade the http library to resolve the Node x19 ECONNRESET error

Fix #104 by using a different http library. I think Axios would be a good library to use.

We need to replace all usage of the request module with axios, and update the corresponding code in the RokuDeploy logic to work with axios.
Make sure to run the device tests to make sure these all work.

npm run test:device

Remove calling pressHomeButton in publish

Pressing home should no longer be needed. We should try removing it to speed up deployments and if needed making an option if it causes issues in some specific cases.

Fix type definition docs

When using roku-deploy in a typescript file, the jsdoc information doesn't show up when using the roku-deploy imports. I believe this is because the index.ts creates local variables and then exports those. We should investigate how to fix this, as the typescript experience is lacking without full documentation info.

Add Signed Package Creation

Currently roku-deploy doesn't handle anything other than doing a regular deployment to the device while developing. In order to help make this the base for a more formalized CI/CD script we need to at minimum be able to make a signed package file for upload to Roku as well. Being able to switch Dev ID would be nice as well but is not required.

Allow negated top-level strings for non rootDir paths

We should allow negated top-level strings that point outside of rootDir.

{
    "files": [
        //currently unsupported, will throw error saying "don't use top level strings to reference files outside of rootDir"
        "!../someExternalDir/**/*",
        //this works. 
        { "src": "!../someExternalDir/**/*"} 
    ]
}

Modify roku-deploy so that both examples above will work

Modify files before zip

I would like to modify some files before zipping the project. I know the possibility of using the incrementBuildNumber parameter but it doesn't work for me because I need to change the version number in several files and I also need to remove one line from another file when build a release. I have modified the file that calls rokudeploy to receive the version as parameter, but now I don't know how to modify those files. Is it possible?

Error downloading the package after using deployAndSignPackage when file name is too long

Adding this issue to help track this bug. We are implementing a temporary work around but ultimately want to fix the underlying cause.

When the outFile configuration value in RokuDeployOptions gets too long the package fails to download.

This is the error output after a ~3 minute timeout:

 Error: ESOCKETTIMEDOUT
    at ClientRequest.<anonymous> (/Users/christianholbrook/work/rokukor/node_modules/postman-request/request.js:1138:19)
    at Object.onceWrapper (node:events:627:28)
    at ClientRequest.emit (node:events:513:28)
    at ClientRequest.emit (node:domain:489:12)
    at Socket.emitRequestTimeout (node:_http_client:839:9)
    at Object.onceWrapper (node:events:627:28)
    at Socket.emit (node:events:525:35)
    at Socket.emit (node:domain:489:12)
    at Socket._onTimeout (node:net:550:8)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)

Integration with BrighterScript?

I'm working on a project where I'm using BrighterScript. Maybe I'm missing something here but I'm trying to use roku-deploy to create my signed production package. During my development workflow, I use BrighterScript either by using a vscode build task to call bsc directly to build and deploy it or, if I need to debug, I use the vscode extension process here.

When it comes time to create a signed package, I'd like to simply use deployAndSignPackage but that doesn't do the bsc transpiling. I know I can manually do a bsc build and THEN call zipPackage, publish, and then signExistingPackage but is there a better way?

EDIT: I think even the method I laid out above wouldn't work for me. As part of my release I would like to increment the manifest build number but it looks like that's only called from createPackage but that will do a full build with BS untranspiled code. :(

release 3.2 seems broken

aside form other issues I get when using bsc, I can no longer install, either..

installing on device with args { host: '192.168.8.204',
username: 'rokudev',
password: 'aaaa',
files: [ '', '**/', '!.zip', '!**/.zip' ],
app_name: 'Smithsonian Channel/5.11',
rootDir: 'build',
rekeySignedPackage: null,
outDir: 'out',
outFile: 'roku-deploy',
signingPassword: null,
retainStagingFolder: true }
deploying to device
There was a problem while instlaling on the device SyntaxError: Unexpected token / in JSON at position 664
[12:06:53] 'deploy' errored after 8.87 ms
[12:06:53] SyntaxError: Unexpected token / in JSON at position 664
at JSON.parse ()
at RokuDeploy.getOptions (/home/george/hope/smc/pot-smithsonian-channel-roku-xm/node_modules/roku-deploy/src/RokuDeploy.ts:711:36)
at RokuDeploy. (/home/george/hope/smc/pot-smithsonian-channel-roku-xm/node_modules/roku-deploy/src/RokuDeploy.ts:653:24)
at step (/home/george/hope/smc/pot-smithsonian-channel-roku-xm/node_modules/roku-deploy/dist/RokuDeploy.js:44:23)
at Object.next (/home/george/hope/smc/pot-smithsonian-channel-roku-xm/node_modules/roku-deploy/dist/RokuDeploy.js:25:53)
at /home/george/hope/smc/pot-smithsonian-channel-roku-xm/node_modules/roku-deploy/dist/RokuDeploy.js:19:71
at new Promise ()
at __awaiter (/home/george/hope/smc/pot-smithsonian-channel-roku-xm/node_modules/roku-deploy/dist/RokuDeploy.js:15:12)
at RokuDeploy.deploy (/home/george/hope/smc/pot-smithsonian-channel-roku-xm/node_modules/roku-deploy/dist/RokuDeploy.js:856:16)
at /home/george/hope/smc/pot-smithsonian-channel-roku-xm/gulpfile.ts:176:22

`signExistingPackage` depends on a staging folder existing

It's not possible to sign a package without pointing to a staging folder in order for the script to read the manifest and get the app name and version.

It would be nice to be able to provide something like signAppNameVersion in the options so the module doesn't need to read the manifest.

Trying to rekey fails if no zip is loaded on the device

Was getting the following error on my Roku:
Error_Could not retrieve Dev ID
Invalid response code: 400

And realized it was because I didn't have a zip file loaded on the device. The Packager tab is where we get the devID is not available until a zip file has been loaded. Not sure the best solution. Could either let the user know, try to get devID a different way, upload a temporary zip file, or just ignore this check in that case.

"inFile" option?

It would be nice to be able to use the nice features of roku-deploy using a pre-packaged app, like:

roku-deploy -infile bin/app.zip -host 1.2.3.4 -password abc

Even using the internal JS API it isn't easy to achieve.

Screenshot support

Add command to capture screenshot from remote roku device.

Command: screenshot-and-save (specify location in user settings or roku-deploy.json)
Command: screenshot-to-clipboard

allow means of excluding map file from zip; but maintaining in staging

.map files are required to facilitate debugging brighterscript files.
They should not be included in zips however, so we can exlclude them in vscode, using the files glob in the launch config.

However:

  • the vscode debugger will not work if .map files are not present in the staging folder
  • forcing us to include them in the zip (as that's the only way to get them into the staging folder)
  • roku sideloading attempts compilation of these .map files, taking up to 1-2 seconds to do so, plus the extra time to copy them onto the device
  • this prevents us from reducing compile times :(

Can we please have a means of exlcuding .map files (or perhaps any glob of files) from the zip; while maintaining them in the staging folder?

Delete sideloaded app prior to publishing

There's a bug on the Roku devices that sometimes causes issues when sideloading a zip file when there's already a sideloaded app. In this situation, it would be helpful to have roku-deploy delete any existing sideloaded app before publishing a new one.

Follow Symlinks?

Hi, so I use submodules that exist outside the channel directory that I need a couple files brought in from. Personally I feel like symlinks would be easiest to use however currently Roku-Deploy zips the actual symlink instead of following it.

Would it be easy to change this?

Created focused/specific interfaces for each function

Many of the roku-deploy public functions take the RokuDeployOptions interface. That's very confusing because it's huge and has many options that many of the functions don't actually need. We should do the following:

  • create a unique interface for each of the public functions that only declare the properties they actually use/require.
  • export the interfaces and give them helpful names so external developers can use them in their code.

Don't normalize file patterns

Currently in normalizeFilesArray, we run the src string through util.standardizePath(). However, this could break glob escapes. All glob paths must use forward slash for directory separators.

This is a breaking change, so it should be handled in v4.

Overhaul the function parameters so they have only the options they need

We currently allow the global roku-deploy options to just be passed around everywhere, which makes all the functions much more confusing because most of the time they don't need most of those options.

We need to create separate objects/interfaces for each function call, so it's clear how to use each one.

Support top-level patterns to external dirs using globstar

Support using top-level patterns to external directories as long as there's at least 1 globstar. Example:

Consider this pattern:
"../thirdPartySDK/**/*"

For this path: ../thirdPartySDK/source/sdk.brs, its final path would be: ./source/sdk.brs because the globstar indicates the start of the relative path portion.

If there are multiple globstars, the first globstar is where the relative pattern will begin.

Update manifest on deploy?

Could this tool or maybe the vscode plugin help with updating the manifest on each deployment?

My idea is to set the build version to the current repository commit hash. But I guess only in the deploy, the source manifest should be untouched of course.

CLI commands for various roku-deploy actions

We should be able to do everything in roku-deploy from the command-line. Things like move-to-stage, create zip from a folder, etc.

Here's a good example of a cli file that this feature can be modelled after.

https://github.com/rokucommunity/ropm/blob/master/src/cli.ts

We want to expose most of the public functions on the RokuDeploy class.

So tasks for this:

Here are a few examples of how we'd use it (args and names might need to be changed, but this gets the point across):

npx roku-deploy copy-to-staging --stagingDir ./staging
npx roku-deploy create-zip --stagingDir ./staging --file app.zip
npx roku-deploy deploy --host 192.168.1.123 --password --file app.zip

Inexplicably cannot deploy if there is no currently deployed app!

If no app is currently side-loaded, then we get:

  Error: Delete Failed: No such file or directory.
      at new FailedDeviceResponseError (node_modules/roku-deploy/dist/Errors.js:52:28)
      at RokuDeploy.checkRequest (node_modules/roku-deploy/dist/RokuDeploy.js:873:19)
      at RokuDeploy.<anonymous> (node_modules/roku-deploy/dist/RokuDeploy.js:830:34)
      at step (node_modules/roku-deploy/dist/RokuDeploy.js:44:23)
      at Object.next (node_modules/roku-deploy/dist/RokuDeploy.js:25:53)
      at fulfilled (node_modules/roku-deploy/dist/RokuDeploy.js:16:58)
      at processTicksAndRejections (node:internal/process/task_queues:94:5)

this is coz the HTTP delete fails - that error should be ignored.
If I get a mo, I'll put a pr up; but it's unlikely

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.