Detect Browserify broken build before committing/deploying - javascript

I'm using Browserify to bundle up my JS before pushing to my Bitbucket repo, and then using Codeship to test the build and push to Heroku.
I'm using Node/Express to serve my app, and in my index.jade I have a <script /> pointing to /dist/index.js.
A couple of times, I've mistakenly pushed my latest code with broken Browserify output, ie. the contents of /dist/index.js will be:
console.error('cannot find module XYZ')
And I've deployed this to my live app. UH OH.
I've put in a very rudimentary test which gets ran on Codeship which I'm hoping should avoid this in the future:
var exit = function() {
process.exit(1)
}
var success = function() {
process.exit(0)
}
var fs = require('fs')
var index
try {
index = fs.readFileSync(__dirname + '/../public/dist/index.js', 'utf-8')
} catch (e) {
exit()
}
if(!index){
exit()
}
var invalid = index.length < 1000
if(invalid){
return exit()
}
success()
I'm just checking if the file exists, and that the contents of the file is over 1000 characters.
Not sure if there's a specific answer to this, but would be a reasonable approach to making sure broken Browserify output never gets committed/deployed?

I haven't used Codeship before, but I have used other similar services. You haven't described how you push - I'm going to assume you're using git.
With git, this becomes easy: write a pre-push hook that will abort the push if something fails. Here's an example from a project I'm working on:
#!/bin/bash
# the protected branches
#
protected_branches='develop master'
# Check if we actually have commits to push
#
commits=`git log #{u}..`
if [ -z "$commits" ]; then
exit 0
fi
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
# is the current branch in the list of protected branchs? if so, then run the
# tests
#
if grep -q "$current_branch" <<< "$protected_branches"; then
# move into the dir containing the tests
#
pushd $(git rev-parse --show-toplevel)/contract >/dev/null
gulp test
RESULT=$?
# back to whatever dir we were in before
#
popd >/dev/null
if [ $RESULT -ne 0 ]; then
echo "-------- Failed Tests"
exit 1
fi
fi
exit 0
This is a modified version of a script I found in this blog post.
Basically, this script checks to see if I'm pushing one of the protected branches and, if so, runs my tests. If those test fail, then the push is aborted.
You could, of course, change the conditions under which the push is aborted. For example, write some code to check & see if your browserify bundle is correct and fail if it's not. You mention checking the length of your bundle - maybe something like length=$(ls -l | cut -c 30-34) and then check the value of length (sorry, I'm not a real bash guru).
The benefit of this approach is that the messed up code never leaves your local machine - you run the test locally and if it fails, the code doesn't get pushed. This is likely to be faster than running in on Codeship's service.

Related

How to populate author, branch, commit, message in Cypres Dashboard in CI with Jenkins?

I'm trying to get the commit information details in the Cypress Dashboard. I haven't been able to accomplish just yet, but I have made some advances though...
I'll describe what I have done so far:
Installed the commit-info npm package by running the command:
npm install --save #cypress/commit-info
Import the plugin in plugin/index.js file like so:
const { commitInfo } = require('#cypress/commit-info');
module.exports = on => {
on('file:preprocessor', file => {
commitInfo().then(console.log);
});
};
Now I get all the information, author, branch, commit & message, in the terminal!:)
However, I still don't have the information details linked to my Cypress Dashboard.
This is what I currently get:
What're the next steps? The documentation is not clear to me...
In our case we run everything inside a docker container. We copy our code into the container but do not copy the .git directory, it's large, time consuming, and we don't need it. #cypress/commit-info assumes there is a .git directory, so since there isn't, it doesn't work.
We overcame this by setting the values cypress expects explicitly in the cypress run command in our Jenkinsfile:
def commitMessage = sh(script:"git log --format=%B -n 1 ${env.GIT_COMMIT}", returnStdout:true).trim()
def commitAuthor = sh(script:"git log --format='%an' -n 1 ${env.GIT_COMMIT}", returnStdout:true).trim()
def commitEmail = sh(script:"git log --format='%ae' -n 1 ${env.GIT_COMMIT}", returnStdout:true).trim()
def cypressVars = "COMMIT_INFO_BRANCH=${env.GIT_BRANCH} COMMIT_INFO_SHA=${env.GIT_COMMIT} COMMIT_INFO_REMOTE=${env.GIT_URL} COMMIT_INFO_MESSAGE=\"${commitMessage}\" COMMIT_INFO_AUTHOR=\"${commitAuthor}\" COMMIT_INFO_EMAIL=${commitEmail}"
// call cypress however you do and include cypressVars as part of the command

Can Emstripten compile the iostream library?

I'm on Ubuntu.
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.2 LTS
Release: 14.04
Codename: trusty
I installed Emscripten.
$ sudo apt-get install emscripten
I wrote the following C++ program:
#include <iostream>
int main(){
printf("hello world\n");
}
It compiles as expected.
$ emcc -O1 -s ASM_JS=1 main.cpp
$
However, when I write a similar program using the iostream facilities:
#include <iostream>
int main(){
std::cout << "hello world" << std::endl;
}
It fails to build.
$ emcc -O1 -s ASM_JS=1 main.cpp
aborting from js compiler due to exception: unknown vector type <4 x i8> | undefined
aborting from js compiler due to exception: unknown vector type <4 x i8> | undefined
aborting from js compiler due to exception: unknown vector type <4 x i8> | undefined
Traceback (most recent call last):
File "/usr/share/emscripten/emscripten.py", line 1352, in <module>
_main(environ=os.environ)
File "/usr/share/emscripten/emscripten.py", line 1340, in _main
temp_files.run_and_clean(lambda: main(
File "/usr/share/emscripten/tools/tempfiles.py", line 39, in run_and_clean
return func()
File "/usr/share/emscripten/emscripten.py", line 1348, in <lambda>
DEBUG_CACHE=DEBUG_CACHE,
File "/usr/share/emscripten/emscripten.py", line 1235, in main
jcache=jcache, temp_files=temp_files, DEBUG=DEBUG, DEBUG_CACHE=DEBUG_CACHE)
File "/usr/share/emscripten/emscripten.py", line 292, in emscript
assert len(output) == 2, 'Did not receive forwarded data in an output - process failed? We only got: ' + output[0][-3000:]
AssertionError: Did not receive forwarded data in an output - process failed? We only got: ((HEAP32[(($1)>>2)])|0);
$3=((($2)-(12))|0);
$4=$3;
$5=((HEAP32[(($4)>>2)])|0);
$6=$this;
$_sum=((($5)+(24))|0);
$7=(($6+$_sum)|0);
$8=$7;
$9=((HEAP32[(($8)>>2)])|0);
$10=($9|0)==0;
if ($10) {
STACKTOP=sp;return (($this)|0);
}
$12=(($__s)|0);
HEAP8[($12)]=0;
$13=(($__s+4)|0);
HEAP32[(($13)>>2)]=$this;
$_sum_i=((($5)+(16))|0);
$14=(($6+$_sum_i)|0);
$15=$14;
$16=((HEAP32[(($15)>>2)])|0);
$17=($16|0)==0;
do {
if ($17) {
$_sum1_i=((($5)+(72))|0);
$19=(($6+$_sum1_i)|0);
$20=$19;
$21=((HEAP32[(($20)>>2)])|0);
$22=($21|0)==0;
if (!($22)) {
$24=((__ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE5flushEv($21))|0);
}
HEAP8[($12)]=1;
$26=((HEAP32[(($1)>>2)])|0);
$27=((($26)-(12))|0);
$28=$27;
$29=((HEAP32[(($28)>>2)])|0);
$_sum1=((($29)+(24))|0);
$30=(($6+$_sum1)|0);
$31=$30;
$32=((HEAP32[(($31)>>2)])|0);
$33=$32;
$34=$32;
$35=((HEAP32[(($34)>>2)])|0);
$36=(($35+24)|0);
$37=((HEAP32[(($36)>>2)])|0);
$38=((FUNCTION_TABLE_ii[($37)&{{{ FTM_ii }}}]($33))|0);
$39=($38|0)==-1;
if (!($39)) {
break;
}
$41=((HEAP32[(($1)>>2)])|0);
$42=((($41)-(12))|0);
$43=$42;
$44=((HEAP32[(($43)>>2)])|0);
$45=(($6+$44)|0);
$46=$45;
$_sum2=((($44)+(16))|0);
$47=(($6+$_sum2)|0);
$48=$47;
$49=((HEAP32[(($48)>>2)])|0);
$50=$49|1;
__ZNSt3__18ios_base5clearEj($46,$50);
}
} while(0);
__ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryD2Ev($__s);
STACKTOP=sp;return (($this)|0);
}
function __ZNSt3__18ios_base33__set_badbit_and_consider_rethrowEv($this){
$this=($this)|0;
var $1=0,$2=0,$3=0,$4=0,$5=0,$6=0,$7=0,label=0;
$1=(($this+16)|0);
$2=((HEAP32[(($1)>>2)])|0);
$3=$2|1;
HEAP32[(($1)>>2)]=$3;
$4=(($this+20)|0);
$5=((HEAP32[(($4)>>2)])|0);
$6=$5&1;
$7=($6|0)==0;
if ($7) {
return;
} else {
___cxa_rethrow();
}
}
function __ZNSt3__113basic_istreamIwNS_11char_traitsIwEEED0Ev($this){
$this=($this)|0;
var $1=0,$2=0,label=0;
$1=(($this+8)|0);
__ZNSt3__18ios_baseD2Ev($1);
$2=$this;
__ZdlPv($2);
return;
}
function __ZNSt3__113basic_istreamIwNS_11char_traitsIwEEED1Ev($this){
$this=($this)|0;
var $1=0,label=0;
$1=(($this+8)|0);
__ZNSt3__18ios_baseD2Ev($1);
return;
}
function __ZTv0_n12_NSt3__113basic_istreamIwNS_11char_traitsIwEEED0Ev($this){
$this=($this)|0;
var $1=0,$2=0,$3=0,$4=0,$5=0,$6=0,$7=0,$_sum=0,$8=0,$9=0,label=0;
$1=$this;
$2=$this;
$3=((HEAP32[(($2)>>2)])|0);
$4=((($3)-(12))|0);
$5=$4;
$6=((HEAP32[(($5)>>2)])|0);
$7=(($1+$6)|0);
$_sum=((($6)+(8))|0);
$8=(($1+$_sum)|0);
$9=$8;
__ZNSt3__18ios_baseD2Ev($9);
__ZdlPv($7);
return;
}
function __ZTv0_n12_NSt3__113basic_istreamIwNS_11char_traitsIwEEED1Ev($this){
$this=($this)|0;
var $1=0,$2=0,$3=0,$4=0,$5=0,$6=0,$_sum=0,$7=0,$8=0,label=0;
$1=$this;
$2=$this;
$3=((HEAP32[(($2)>>2)])|0);
$4=((($3)-(12))|0);
$5=$4;
$6=((HEAP32[(($5)>>2)])|0);
$_sum=((($6)+(8))|0);
$7=(($1+$_sum)|0);
$8=$7;
__ZNSt3__18ios_baseD2Ev($8);
return;
}
Traceback (most recent call last):
File "/usr/bin/emcc", line 1864, in <module>
final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args)
File "/usr/share/emscripten/tools/shared.py", line 1276, in emscripten
assert os.path.exists(filename + '.o.js') and len(open(filename + '.o.js', 'r').read()) > 0, 'Emscripten failed to generate .js: ' + str(compiler_output)
AssertionError: Emscripten failed to generate .js:
I was under the impression that Emscripten has come a long way, and is capable of compiling entire C++ games for the browser! Is there some kind of flag or configuration I missed in order to sucessfully compile portions of the C++ standard library? I know that clang/gcc compilers will link against the C++ standard shared library by default. Does the issue have something to do with that you think?
I have also tried using the command em++ in place of emcc and recieved the same error message.
If relevant, here is the default configuration that was built when running emscripten for the first time:
$ cat ~/.emscripten
# Note: If you put paths relative to the home directory, do not forget os.path.expanduser
import os
# this helps projects using emscripten find it
EMSCRIPTEN_ROOT = os.path.expanduser(os.getenv('EMSCRIPTEN') or '/usr/share/emscripten') # directory
LLVM_ROOT = os.path.expanduser(os.getenv('LLVM') or '/usr/bin') # directory
PYTHON = os.path.expanduser(os.getenv('PYTHON') or '/usr/bin/python2') # executable
# See below for notes on which JS engine(s) you need
NODE_JS = os.path.expanduser(os.getenv('NODE') or '/usr/bin/node') # executable
SPIDERMONKEY_ENGINE = [os.path.expanduser(os.getenv('SPIDERMONKEY') or 'js')] # executable
V8_ENGINE = os.path.expanduser(os.getenv('V8') or 'd8') # executable
JAVA = 'java' # executable
TEMP_DIR = '/tmp'
CRUNCH = os.path.expanduser(os.getenv('CRUNCH') or 'crunch') # executable
#CLOSURE_COMPILER = '..' # define this to not use the bundled version
########################################################################################################
# Pick the JS engine to use for running the compiler. This engine must exist, or
# nothing can be compiled.
#
# Recommendation: If you already have node installed, use that. Otherwise, build v8 or
# spidermonkey from source. Any of these three is fine, as long as it's
# a recent version (especially for v8 and spidermonkey).
COMPILER_ENGINE = NODE_JS
#COMPILER_ENGINE = V8_ENGINE
#COMPILER_ENGINE = SPIDERMONKEY_ENGINE
# All JS engines to use when running the automatic tests. Not all the engines in this list
# must exist (if they don't, they will be skipped in the test runner).
#
# Recommendation: If you already have node installed, use that. If you can, also build
# spidermonkey from source as well to get more test coverage (node can't
# run all the tests due to node issue 1669). v8 is currently not recommended
# here because of v8 issue 1822.
JS_ENGINES = [NODE_JS] # add this if you have spidermonkey installed too, SPIDERMONKEY_ENGINE]
I can't seem to find a way to get the basic C++ program above to successfully compile.
First, your program compiles fine for me with emcc. Your original program (with printf) causes emcc to assume it is compiling C code and as such it will auto-include stdio.h as C does. Your second program is having more trouble, probably due to an install error (for me I had an issue like this because my version of LLVM doesn't line up with the exact version Emscripten needed.)
Unfortunately, my understanding is that this is a common problem with emscripten and auto installers like apt-get -- I had the problem with both port and brew on my Mac.
The solution is to get Emscripten through the SDK, which bundles all of the sensitive pieces together: https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
Follow the instructions there carefully. The two problems I ran into were that it expects Python 2 to be called python2 on your system and the script to adjust your default path assumes you're using bash (if you are, it should work fine.)

Bulk fix missing semicolons that JSHints finds in project

I have a project of 100+ javascript files each with 1-5 missing semicolons according to JSHint (as a result multiple people working on the project with different conventions).
I'd like to bulk fix everything as it's not practical to fix each individually. I've found this: https://github.com/jshint/fixmyjs but I don't see a way only fix semicolons without 'fixing' other things (tabs -> spaces, for example).
Does anyone know of way to do this? I'm comfortable with the possibility that it might cause breakage/introduce bugs. I've look over the errors and they look pretty routine.
I really hope you like this as a solution. Be vary careful that you verify with jshint again after you've fixed the issues. And out of curiosity, how did you manage to get so many broken javascript files?
#!/bin/sh
function fixFile {
for i in `jshint $1 | grep -i "Missing semicolon" \
| sed -e 's/\([^0-9]*\)\([0-9]*\)\(.*$\)/\2/'`;
do
sed -i $1 -e $i's/\(\s*\)$/;/'
done
}
fixFile $1
The above uses jshint to produce some error lines, greps them for the missing semicolon errors only, extracts the line number of each error, then seds the file in place on that line to remove any trailing whitespace and replace it with a semicolon.
The file...
var a = 5, c = 4
function helloWorld() {
if (this == doesntmakesense)
console.log('hello' + 'world');
}
console.log(a+c);
console.log('finished')
...becomes...
var a = 5, c = 4;
function helloWorld() {
if (this == doesntmakesense)
console.log('hello' + 'world');
}
console.log(a+c);
console.log('finished');
Where petty semantic errors are ignored, and only semicolons treated.
I'd save the bash script as something like fixFile.sh and then run find . -name "*.js" -exec ./fixFile.sh {} \;
But please commit beforehand. All commands are run at your own risk ;)
There is a safer way of adding missing semicolons than using regular expressions. Use the following steps to configure fixmyjs to only fix semicolons as originally asked by Evan:
Install fixmyjs
npm install fixmyjs -g
Create a fixmyjs config file fixmyjs-config with the following content
{ "asi": false }
Run fixmyjs
fixmyjs --config [fixmyjs-config] --legacy yourfile.js
Reference: https://github.com/jshint/fixmyjs/issues/86
Google Closure JS Linter has a program that comes with it, able to correct some of the more regular violations such as this one I believe, it's named fixjsstyle (python btw)

Console.log debug messages managing

My JS code is usually full of console.log() debug messages. Sometimes it is better to turn them off, or to turn off some part of them.
I can, for example, wrap console.log() statement in some function with conditions which are defined by some constants. Is it the best way to manage debug output or are more elegant alternatives?
Bunyan logging module is popular for node.js
Example code hi.js:
var bunyan = require('bunyan');
var log = bunyan.createLogger({name: 'myapp'});
log.info('hi');
log.warn({lang: 'fr'}, 'au revoir');
Output:
{"name":"myapp","hostname":"localhost","pid":40161,"level":30,"msg":"hi","time":"2013-01- 04T18:46:23.851Z","v":0}
{"name":"myapp","hostname":"localhost","pid":40161,"level":40,"lang":"fr","msg":"au revoir","time":"2013-01-04T18:46:23.853Z","v":0}
You can then filtering from command lines:
$ node hi.js | bunyan -l warn
[2013-01-04T19:08:37.182Z] WARN: myapp/40353 on localhost: au revoir (lang=fr)
Wrapping console.log into a function works well. But notice that there are also a lot of logging utilities out there for javascript. A little google on "js logger" may yield suitable results.
If you're using Node.js then debug is extremely effective as an alternative to console.log()
It's basically a substitute for console.log() except you can enable it at the command line with the DEBUG environment variable based on how you've initialized it in each file.
Let's say I have a project with a couple of files referenced from my index.js file:
one.js
var debug = require('debug')('one-one');
var func = function() {
debug('func');
}
two.js
var debug = require('debug')('one-two');
var func = function() {
debug('func');
}
You've initialized debug with the name "one-one" in the first file and "one-two" in the second file.
On the command line I can run them like this:
node index.js
Result: no debug output. However, if I run it like this:
DEBUG=* node index.js
The both the debug statements will get written out, however, in different colors and with the debug name (one-one or one-two) so I can tell which file they came from.
Now let's say you want to narrow it down a bit more. You could run:
DEBUG=*-two node index.js
To only get output from debug that's been set with "-two" at the end of the name or
DEBUG=one-* node index.js
to get everything starting with "one-"
You can also say that you want everything, or a set of things, or exclude patterns or sets. To exclude something you precede it with a dash, an example:
DEBUG=one*,monkey*,-monkey:banana,-elephant,-chimp:* node index.js
This will include everything starting with "one" or "monkey" and exclude anything called "monkey:banana", or "elephant" or starting with "chimp:"
If you wanted to exclude everything except then:
DEBUG=*,-pattern1,-pattern2 node index.js
JS logger is quite good and lightweight tool with flixible settings for log messages levels and several predefined logging levels (DEBUG, INFO, WARN, ERROR).

execute some code and then go into interactive node

Is there a way to execute some code (in a file or from a string, doesn't really matter) before dropping into interactive mode in node.js?
For example, if I create a script __preamble__.js which contains:
console.log("preamble executed! poor guy!");
and a user types node __preamble__.js they get this output:
preamble executed! poor guy!
> [interactive mode]
Really old question but...
I was looking for something similar, I believe, and found out this.
You can open the REPL (typing node on your terminal) and then load a file.
Like this: .load ./script.js.
Press enter and the file content will be executed. Now everything created (object, variable, function) in your script will be available.
For example:
// script.js
var y = {
name: 'obj',
status: true
};
var x = setInterval(function () {
console.log('As time goes by...');
}, 5000);
On the REPL:
//REPL
.load ./script.js
Now you type on the REPL and interact with the "living code".
You can console.log(y) or clearInterval(x);
It will be a bit odd, cause "As time goes by..." keep showing up every five seconds (or so).
But it will work!
You can start a new repl in your Node software pretty easily:
var repl = require("repl");
var r = repl.start("node> ");
r.context.pause = pauseHTTP;
r.context.resume = resumeHTTP;
From within the REPL you can then call pause() or resume() and execute the functions pauseHTTP() and resumeHTTP() directly. Just assign whatever you want to expose to the REPL's context member.
This can be achieved with the current version of NodeJS (5.9.1):
$ node -i -e "console.log('A message')"
The -e flag evaluates the string and the -i flag begins the interactive mode.
You can read more in the referenced pull request
node -r allows you to require a module when REPL starts up. NODE_PATH sets the module search path. So you can run something like this on your command line:
NODE_PATH=. node -r myscript.js
This should put you in a REPL with your script loaded.
I've recently started a project to create an advanced interactive shell for Node and associated languages like CoffeeScript. One of the features is loading a file or string in the context of the interpreter at startup which takes into account the loaded language.
http://danielgtaylor.github.com/nesh/
Examples:
# Load a string (Javascript)
nesh -e 'var hello = function (name) { return "Hello, " + name; };'
# Load a string (CoffeeScript)
nesh -c -e 'hello = (name) -> "Hello, #{name}"'
# Load a file (Javascript)
nesh -e hello.js
# Load a file (CoffeeScript)
nesh -c -e hello.coffee
Then in the interpreter you can access the hello function.
Edit: Ignore this. #jaywalking101's answer is much better. Do that instead.
If you're running from inside a Bash shell (Linux, OS X, Cygwin), then
cat __preamble__.js - | node -i
will work. This also spews lots of noise from evaluating each line of preamble.js, but afterwords you land in an interactive shell in the context you want.
(The '-' to 'cat' just specifies "use standard input".)
Similar answer to #slacktracer, but if you are fine using global in your script, you can simply require it instead of (learning and) using .load.
Example lib.js:
global.x = 123;
Example node session:
$ node
> require('./lib')
{}
> x
123
As a nice side-effect, you don't even have to do the var x = require('x'); 0 dance, as module.exports remains an empty object and thus the require result will not fill up your screen with the module's content.
Vorpal.js was built to do just this. It provides an API for building an interactive CLI in the context of your application.
It includes plugins, and one of these is Vorpal-REPL. This lets you type repl and this will drop you into a REPL within the context of your application.
Example to implement:
var vorpal = require('vorpal')();
var repl = require('vorpal-repl');
vorpal.use(repl).show();
// Now you do your custom code...
// If you want to automatically jump
// into REPl mode, just do this:
vorpal.exec('repl');
That's all!
Disclaimer: I wrote Vorpal.
There isn't a way do this natively. You can either enter the node interactive shell node or run a script you have node myScrpt.js. #sarnold is right, in that if you want that for your app, you will need to make it yourself, and using the repl toolkit is helpful for that kind of thing
nit-tool lets you load a node module into the repl interactive and have access to inner module environment (join context) for development purposes
npm install nit-tool -g
First I tried
$ node --interactive foo.js
but it just runs foo.js, with no REPL.
If you're using export and import in your js, run npm init -y, then tell node that you're using modules with the "type": "module", line -
{
"name": "neomem",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "home.js",
"keywords": [],
"author": "",
"license": "ISC"
}
Then you can run node and import a file with dynamic import -
$ node
Welcome to Node.js v18.1.0.
Type ".help" for more information.
> home = await import('./home.js')
[Module: null prototype] {
get: [AsyncFunction: get],
start: [AsyncFunction: start]
}
> home.get('hello')
Kind of a roundabout way of doing it - having a command line switch would be nice...

Categories

Resources