Run grunt task asynchronously before another task - javascript

I have a gruntfile setup so that I can develop my local angularjs frontend while forwarding all api requests to a java middle tier hosted seperately on the network.
This works great except the location of the server changes every few days and I have to continuously update the gruntfile with the latest server location.
The latest server location can be found by a URL shortening service that forwards to the correct location, so I can fetch it with this grunt task/node.js code:
grunt.registerTask('setProxyHost', 'Pings the url shortener to get the latest test server', function() {
request('http://urlshortener/devserver', function(error, response, body) {
if (!error) {
var loc = response.request.uri.href;
if (loc.slice(0, 7) === 'http://') {
proxyHost = loc.slice(7, loc.length - 1);
}
}
});
});
Of course this is asynchonous, and when I run it, grunt has already setup the proxy by the time the request completes.
How can I run this nodejs request synchronously or block grunt until it completes? This is just for development so hacky solutions welcomed.
Thanks
EDIT:
Great answer Cory, that has mostly solved the problem as grunt now waits for the task to complete before continuing. One last issue is that I can't access that config from the initConfig for setting the proxy as initConfig runs first:
module.exports = function(grunt) {
[...]
grunt.initConfig({
connect: {
proxies: [{
host: grunt.config.get('proxyHost')
This post (Access Grunt config data within initConfig()) outlines the issue but I'm not sure how I could run the request synchronously outside of a task?
EDIT2 [solved]:
Corys answer + this post Programmatically pass arguments to grunt task? solved the issue for me.
module.exports = function(grunt) {
[...]
grunt.initConfig({
connect: {
proxies: [{
host: '<%= proxyHost %>',

Instead of running the task synchronously, you can easily run the task asynchronously & share data between tasks through the grunt config object.
1. Run a task asynchronously
To run a task asynchronously, you must first inform Grunt that the task is going to be async by calling this.async() This async call returns a "done function" that you'll use to tell Grunt whether the task has passed or failed. You can complete the task by passing the handler true and fail it by passing it an error, or false.
Async Task:
module.exports = function(grunt) {
grunt.registerTask('foo', 'description of foo', function() {
var done = this.async();
request('http://www...', function(err, resp, body) {
if ( err ) {
done(false); // fail task with `false` or Error objects
} else {
grunt.config.set('proxyHost', someValue);
done(true); // pass task
}
});
});
}
2. Share data between tasks
That grunt.config.set() bit (in the code above) is probably the easiest way to share values between tasks. Since all tasks share the same grunt config, you simply set a property on the config and then read it from the following tasks via grunt.config.get('property')
Following Task
module.exports = function(grunt) {
grunt.registerTask('bar', 'description of bar', function() {
// If proxy host is not defined, the task will die early.
grunt.config.requires('proxyHost');
var proxyHost = grunt.config.get('proxyHost');
// ...
});
}
The grunt.config.requires bit will inform grunt that the task has config dependencies. This is useful in scenarios where tasks go untouched for a long time (very common) and the intricacies are forgotten about. If you decide on changing the async task (rename the variable? dev_proxyHost, prod_proxyHost?) the following task will gracefully inform you that proxyHost could not be found.
Verifying property proxyHost exists in config...ERROR
>> Unable to process task.
Warning: Required config property "proxyHost" missing. Use --force to continue.
3. Your code, async
grunt.registerTask('setProxyHost', 'Pings the url shortener to get the latest test server', function() {
var done = this.async(),
loc,
proxyHost;
request('http://urlshortener/devserver', function(error, response, body) {
if (error) {
done(error); // error out early
}
loc = response.request.uri.href;
if (loc.slice(0, 7) === 'http://') {
proxyHost = loc.slice(7, loc.length - 1);
// set proxy host on grunt config, so that it's accessible from the other task
grunt.config.set('proxyHost', proxyHost);
done(true); // success
}
else {
done(new Error("Unexpected HTTPS Error: The devserver urlshortener unexpectedly returned an HTTPS link! ("+loc+")"));
}
});
});
Then from your proxy task, you can retrieve this proxyHost value via the following
var proxyHost = grunt.config.get('proxyHost');

Related

createDeployment() with Kubernetes JavaScript client

I am trying to create a deployment or replicaSet with the Kubernetes Javascript client. The Kubernetes javascript client documentation is virtually non-existent.
Is there any way to achieve this?
Assuming that by:
createDeployment()
you are referring to: createNamespacedDeployment()
You can use below code snippet to create a Deployment using Javascript client library:
const k8s = require('#kubernetes/client-node');
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const k8sApi = kc.makeApiClient(k8s.AppsV1Api); // <-- notice the AppsV1Api
// Definition of the deployment
var amazingDeployment = {
metadata: {
name: 'nginx-deployment'
},
spec: {
selector: {
matchLabels: {
app: 'nginx'
}
},
replicas: 3,
template: {
metadata: {
labels: {
app: 'nginx'
}
},
spec: {
containers: [
{
name: 'nginx',
image: 'nginx'
} ]
}
}
}
};
// Sending the request to the API
k8sApi.createNamespacedDeployment('default', amazingDeployment).then(
(response) => {
console.log('Yay! \nYou spawned: ' + amazingDeployment.metadata.name);
},
(err) => {
console.log('Oh no. Something went wrong :(');
// console.log(err) <-- Get the full output!
}
);
Disclaimer!
This code assumes that you have your ~/.kube/config already configured!
Running this code for the first time with:
$ node deploy.js
should output:
Yay!
You spawned: nginx-deployment
You can check if the Deployment exists by:
$ kubectl get deployment nginx-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 6m57s
Running this code once again will output (deployment already exists!):
Oh no. Something went wrong :(
Additional resources:
Github.com: Kubernetes-client: Javascript
Be careful when you try to deploy a different kinds of resources such as deployment or service.
You need to correctly specify the API version.
const k8sApi = kc.makeApiClient(k8s.AppsV1Api) or (k8s.CoreV1Api) for namespace and etc.
First, you create a kube config object and then create the associated API type. I.e,
import k8s from '#kubernetes/client-node';
const kubeConfig = new k8s.KubeConfig();
kubeConfig.loadFromCluster(); // Or whatever method you choose
const api = kubeConfig.makeApiClient(k8s.CoreV1Api); // Or whatever API
// you'd like to
// use.
const namespace = 'default';
const manifest = new k8s.V1ConfigMap();
// ... additional manifest setup code...
await api.createNamespacedConfigMap(namespace, manifest);
This is the gist of it. If you'd like, I recently created a library with the intention of simplifying interactions with the kubernetes javascript api and it can be found here:
https://github.com/ThinkDeepTech/k8s
If it doesn't help you directly, perhaps it can serve as an example of how to interact with the API. I hope that helps!
Also, make sure the application executing this code has the necessary permissions (i.e, the K8s Role, RoleBinding and ServiceAccount configs) necessary to perform the actions you're attempting. Otherwise, it'll error out.

Getting test results when creating a Karma server programmatically

I am trying to run multiple Karma test files in parallel from inside a Node script and get to know which tests are passing or failing. Right now what I have is this:
const exec = require("child_process").exec;
exec("karma start " + filename, (error, stdout, stderr) => {
// handle errors and test results...
});
The code above works well, and I can get the information on tests passed or failed from stdout. However, it requires having installed Karma and all of the associated dependencies (reporters, browser launchers, etc.) globally. I am looking for a solution that doesn't require me to install all dependencies globally.
My first thought was this:
const karma = require("karma");
const server = new karma.Server(config, () => {
// some logic
});
However, when trying this other approach, I have been unable to gather the test results programmatically.
When using new karma.Server(), is there any way in which I could know which tests have passed or failed (and, ideally, a stack trace of the error)? Alternatively, is there any other way in which I can execute my tests and get the desired information programmatically without the need to install dependencies globally?
Actually, changing the exec line to this seems to do the trick:
exec("node node_modules/karma/bin/karma start " + filename, (error, stdout, stderr) => {
It turns out I'd only need to run the locally installed version of Karma instead of the global one. :-)

How to halt a series of tasks but continue watching files in Gulp?

I have a Gulp task that lints Javascript files before injecting them into a HTML page. I'd like the files not to be injected if a linting error is found. So if an error appears in the first task, cancel all subsequent tasks.
The caveat is that this task is run by gulp.watch and I'd like the watch to continue to monitor the files and inject them if the linting errors are resolved.
Is this possible in gulp? Plugins are acceptable.
Gulpfile below:
var gulp = require('gulp');
var runSequence = require('run-sequence');
//(plugin declarations removed for brevity)
gulp.task('eslint', function() {
return gulp.src(config.lint)
.pipe($.cached('eslint'))
.pipe($.eslint())
.on('error', $.gutil.log)
.pipe($.eslint.format());
});
gulp.task('inject:resources', function() {
return gulp.src(config.src.templates)
.pipe(
$.inject(gulp.src(config.dist.scripts + '/all*.js',
{read: false}),
{
ignorePath: config.dist.public,
addRootSlash: false,
name: 'scripts'
}
))
.pipe(gulp.dest(config.dist.public));
});
gulp.task('watch:js', function(callback) {
runSequence('eslint', 'inject:resources');
});
gulp.task('watch', function() {
gulp.watch(config.src.scripts, ['watch:js']);
});
First you need to make eslint fail when any of your files produces an error. You can do that by placing eslint.failAfterError() at the end of your stream:
gulp.task('eslint', function() {
return gulp.src(config.lint)
.pipe($.cached('eslint'))
.pipe($.eslint())
.on('error', $.gutil.log)
.pipe($.eslint.format())
.pipe($.eslint.failAfterError());
});
When your eslint task fails the subsequent inject:resources task will not be executed by runSequence.
Next you need to make the callback in your watch:js task available to runSequence, otherwise gulp will not notice when watch:js has finished (and since you can't run the same task in parallel with itself this would effectively prevent watch:js from being started again):
gulp.task('watch:js', function(callback) {
runSequence('eslint', 'inject:resources', callback);
});
The only downside to this is that the above will produce an ugly stack trace that doesn't really provide any useful additional info. If you want to prevent that you can just "swallow" the error that is being passed up the callback chain like this:
gulp.task('watch:js', function(callback) {
runSequence('eslint', 'inject:resources', function(err) {
callback();
});
});

How to run node js application programmatically using forever

I need to run the set of node js files which contains the configuration information where It has to run typically port number and IP address then using the forever in node.js I need to run the script in the terminal with the configuration without having any manual input.
For Programmatic approach , you can use Forever-Moniter
var forever = require('forever-monitor');
var child = new (forever.Monitor)('your-filename.js', {
max: 3,
silent: true,
options: []
});
child.on('exit', function () {
console.log('your-filename.js has exited after 3 restarts');
});
child.start();
You could make use of the child_process module. Check the doc, there're some useful information there: http://nodejs.org/api/child_process.html
To give a brief example
var exec = require('child_process').exec;
exec('forever', function callback(error, stdout, stderr){
// cb
});
If you don't need a callback / don't want to wait for the execution:
var exec = require('child_process').exec('forever').unref();
Was that helpful?
Best
Marc
Edit: Ok, not sure if I really got the point of your question, but my answer combined with https://stackoverflow.com/a/23871739/823851 might offer a good solution.
Usage:
forever start hello.js to start a process.
forever list to see list of all processes started by forever
forever stop hello.js to stop the process, or forever stop 0 to stop the process with index 0 (as shown by forever list).
node-config is a good module for managing different configurations of a Node.js app.
For example, to make a "production" config, /config/production.json would contain:
{
"port" : "3000",
"ip" : "192.168.1.1"
}
In one of your node application JS files:
config = require('config')
....
var port = config.port;
var ip = config.ip;
And to launch the app in this configuration, just first set your NODE_ENV to production from the shell before running your app.
export NODE_ENV=production
forever start app.js
Make additional config JSON files as needed for each of your environments. default.json is used when no environment is specified.

Configure a separate Grunt instance in a test

I have been writing a small grunt plugin, and now I am stuck trying to test the plugin end-to-end. What I would like to accomplish is this
Write a test case that configures a grunt instance with a minimal grunt config for my plugin and runs that task
Test that the file produced equals the intended output
Run that test automatically when running grunt nodeunit
So far, I seem stuck on configuring an individual Grunt instance, as the new instance seems to share configuration with that of the already loaded Grunt instance.
I got something like this in my plugin_test.js
var testGrunt = require('grunt');
exports.codekit = {
setUp: function(done) {
testGrunt.initConfig({
myPlugin : {
// the config
}
});
testGrunt.task.run(['myPlugin']);
done();
},
basic_parsing_works: function(test) {
test.expect(1); // no idea what this does
test.equal(1,1,'basic test');
//var actual = testGrunt.file.read('tmp/test01_result.html');
//var expected = testGrunt.file.read('expected/test01_expected.html');
//test.equal(actual, expected, 'should parse file.');
test.done();
}
};
The problem is that when I run the task for myPlugin it uses the configuration loaded in the "outer" (already running) Grunt instance. Even though I have specifically created a new Grunt instance under a different name (testGrunt).
Is there a way to avoid this?

Categories

Resources