source: Dev/trunk/Gruntfile.js @ 533

Last change on this file since 533 was 533, checked in by hendrikvanantwerpen, 10 years ago

Add watch command to ease client development.

File size: 12.2 KB
Line 
1/** Gruntfile - control build and deploy tasks
2 */
3
4var _ = require('underscore');
5
6module.exports = function(grunt) {
7
8    // TASKS
9
10    // default task
11    grunt.registerTask('default', ['compile']);
12    // development
13    grunt.registerTask('compile',
14                       "Lint all sources and compile Coffee and LESS sources.",
15                       ['path-check:svn'
16                       ,'svn-ignore:compile'
17                       ,'jshint:lint-sources'
18                       ,'htmlhint:lint'
19                       ,'coffeelint:lint'
20                       ,'jsonlint:lint'
21                     //,'tv4:lint'
22                       ,'less:compile'
23                       ,'usebanner:generated-css'
24                       ,'coffee:compile'
25                       ,'usebanner:generated-js'
26                       ,'jshint:lint-generated'
27                     //,'amd-check' // too smart about plugins, r.js can't find them
28                       ]);
29    grunt.registerTask('watch-client',
30                       "Watch client source and recompile when things change.",
31                       ['watch:client']);
32    grunt.registerTask('run',
33                       "Compile and start the server locally with foreman.",
34                       ['path-check:foreman'
35                       ,'compile'
36                       ,'foreman:run-src']);
37    grunt.registerTask('build',
38                       "Compile and make a Dojo build of the client (compress sources).",
39                       ['compile'
40                       ,'clean:build'
41                       ,'copy:build'
42                       ,'dojo:build'
43                       ]);
44    grunt.registerTask('run-build',
45                       "Make a build and start server from build locally with foreman.",
46                       ['path-check:foreman'
47                       ,'build'
48                       ,'foreman:run-build']);
49    grunt.registerTask('deploy',
50                       "Make a build and deploy it to Heroku.",
51                       ['path-check:svn'
52                       ,'path-check:git'
53                       ,'svninfo'
54                       ,'build'
55                       ,'git_deploy:deploy-build']);
56    grunt.registerTask('deploy-src',
57                       "Deploy sources to Heroku (FOR DEBUGGING ONLY).",
58                       ['path-check:svn'
59                       ,'path-check:git'
60                       ,'svninfo'
61                       ,'compile'
62                       ,'git_deploy:deploy-src']);
63    // database management
64    grunt.registerTask('db-backup-cloud-to-dated-local',
65                       "Backup the Heroku database to a timestamped local database.",
66                       ['path-check:heroku'
67                       ,'heroku-config'
68                       ,'http:db-backup-cloud-to-dated-local']);
69    grunt.registerTask('db-pull-cloud-to-local',
70                       "Synchronize local database with the Heroku database (pull changes).",
71                       ['path-check:heroku'
72                       ,'heroku-config'
73                       ,'http:db-pull-cloud-to-local']);
74    grunt.registerTask('db-push-local-to-cloud',
75                       "Synchronize the Heroku database with the local database (push changes).",
76                       ['path-check:heroku'
77                       ,'heroku-config'
78                       ,'http:db-push-local-to-cloud']);
79    grunt.registerTask('cloudant-url',
80                       "Print the Cloudant URL to the console.",
81                       ['path-check:heroku'
82                       ,'heroku-config'
83                       ,'print:herokuConfig.CLOUDANT_URL:CLOUDANT_URL'
84                       ]);
85    grunt.registerTask('#',
86                       "---\nTASKS BELOW ARE INTERNAL AND SHOULD NOT USUALLY BE CALLED FROM THE COMMAND-LINE\n---",
87                       []);
88
89    // FILES AND FOLDERS
90   
91    var srcDir   = 'src/';
92    var buildDir = 'build/';
93    var coffeeMap = grunt.file.expandMapping(
94        [ 'client/qed-client/**/*.coffee', 'server/**/*.coffee' ],
95        srcDir,
96        { cwd: srcDir, ext: '.js' });
97    var lessMap = grunt.file.expandMapping(
98        [ 'client/qed-client/css/qed.less' ],
99        srcDir,
100        { cwd: srcDir, ext: '.css' });
101
102    var mode = process.env.QED_ENV || 'dev';
103    var dbNames = {
104        dev: 'qed-dev',
105        production: 'qed'
106    };
107    if ( !( mode in dbNames ) ) {
108        throw new Error("Unknown mode "+mode+" specified.");
109    }
110
111    // TASK CONFIG
112
113    grunt.initConfig({
114        localDbURL: "http://localhost:5984",
115        dbName: dbNames[mode],
116        timestamp: "<%= grunt.template.today(\"UTC:yyyymmdd't'HHMMss'z'\") %>",
117
118        'amd-check': {
119            files: [ srcDir+'client/qed-client/**/*.js' ]
120        },
121        clean: {
122            build: { src: [buildDir] }
123        },
124        coffee: {
125            options: { bare: true },
126            compile: { files: coffeeMap }
127        },
128        coffeelint: {
129            lint: { options: require('./'+srcDir+'.coffeelint.json'),
130                    files: coffeeMap }
131        },
132        copy: {
133            build: { files: [{ expand: true,
134                               cwd: srcDir,
135                               src: ['**', '!client/*/**' ],
136                               dest: buildDir }]}
137        },
138        dojo: {
139            build: { options: { dojo: srcDir+'client/dojo/dojo.js',
140                                profile: srcDir+'client/client.profile.js',
141                                releaseDir: '../../'+buildDir }}
142        },
143        foreman: {
144            'run-src': {
145                options: {
146                    cwd: srcDir
147                }
148            },
149            'run-build': {
150                options: {
151                    cwd: buildDir
152                }
153            }
154        },
155        git_deploy: {
156            'deploy-build': {
157                options: {
158                    url: 'git@heroku.com:quod-erat.git',
159                    branch: 'master',
160                    message: "Build deployment of revision <%= svninfo.rev %> on <%= grunt.template.today() %>."
161                },
162                src: buildDir
163            },
164           
165            'deploy-src': {
166                options: {
167                    url: 'git@heroku.com:quod-erat.git',
168                    branch: 'master',
169                    message: "Source deployment of revision <%= svninfo.rev %> on <%= grunt.template.today() %>."
170                },
171                src: srcDir
172            }
173        },
174        'heroku-config': {
175            options: {
176                app: 'quod-erat',
177                keys: ['CLOUDANT_URL']
178            }
179        },
180        htmlhint: {
181            options: { htmlhintrc: srcDir+".htmlhintrc" },
182            lint: { files: [{ expand: true,
183                              cwd: srcDir,
184                              src: ['client/*.html', 'client/qed-client/**/*.html'] }]}
185        },
186        http: {
187            'db-backup-cloud-to-dated-local': {
188                options: {
189                    url: "<%= localDbURL %>/_replicate",
190                    method: 'POST',
191                    body: {
192                        source: "<%= herokuConfig.CLOUDANT_URL %>/<%= dbName %>",
193                        target: "<%= dbName %>-<%= timestamp %>",
194                        create_target: true
195                    },
196                    json: true
197                }
198            },
199            'db-pull-cloud-to-local': {
200                options: {
201                    url: "<%= localDbURL %>/_replicate",
202                    method: 'POST',
203                    body: {
204                        source: "<%= herokuConfig.CLOUDANT_URL %>/<%= dbName %>",
205                        target: "<%= dbName %>",
206                        create_target: true
207                    },
208                    json: true
209                }
210            },
211            'db-push-local-to-cloud': {
212                options: {
213                    url: "<%= localDbURL %>/_replicate",
214                    method: 'POST',
215                    body: {
216                        source: "<%= dbName %>",
217                        target: "<%= herokuConfig.CLOUDANT_URL %>/<%= dbName %>",
218                        create_target: true
219                    },
220                    json: true
221                }
222            }
223        },
224        jshint: {
225            'lint-sources': { options: { jshintrc: srcDir+".jshintrc" },
226                              files: { src: [ srcDir+'client/qed-client/**/*.js', srcDir+'server/**/*.js' ].concat(exclude(dest(coffeeMap))) } },
227            'lint-generated': { options: { jshintrc: srcDir+".jshintrc-generated" },
228                                files: { src: dest(coffeeMap) } }
229        },
230        jsonlint: {
231            'lint': { files: { src: [ srcDir+'client/qed-client/**/*.json', srcDir+'server/**/*.json' ] } }
232        },
233        less: {
234            options: { strictImports: false,
235                       dumpLineNumbers: "all" },
236            compile: { files: lessMap }
237        },
238        'path-check': {
239            'heroku': {
240                src: ['heroku']
241            },
242            'foreman': {
243                src: ['foreman']
244            },
245            'svn': {
246                src: ['svn']
247            },
248            'git': {
249                src: ['git']
250            }
251        },
252        requirejs: {
253            basePath: srcDir+'client/',
254            packages: [
255                { name: "dojo", location: "dojo" },
256                { name: "dijit", location: "dijit" },
257                { name: "dojox", location: "dojox" },
258                { name: "qed-client", location: "qed-client" }
259            ]
260        },
261        'svn-ignore': {
262            compile: {
263                files: { src: dest(coffeeMap).concat(dest(lessMap)) }
264            }
265        },
266        'svn-ignore-clean': {
267            clean: {
268                files: [{
269                    expand: true,
270                    cwd: srcDir,
271                    src: ['**', '!node_modules/**', '!client/dojo/**', '!client/dijit/**', '!client/dojox/**', '!client/util/**'],
272                    filter: 'isDirectory'
273                }]
274            }
275        },
276        tv4: {
277            lint: {
278                options: {
279                    root: grunt.file.readJSON('json-schema-draft-04.json'),
280                    multi: true
281                },
282                src: [srcDir+'server/config/couchdb-schema.json']
283            }
284        },
285        usebanner: {
286            'generated-css': { options: { position: 'top',
287                                          banner: '/* This CSS file is generated. All edits will be lost on recompile. */'},
288                               files: { src: dest(lessMap) }},
289            'generated-js': { options: { position: 'top',
290                                         banner: '/* This JS file is generated, All edits will be lost on recompile. */'},
291                               files: { src: dest(coffeeMap) }}
292        },
293        watch: {
294            client: {
295                files: [ srcDir+'client/qed-client/**' ],
296                tasks: [ 'compile' ]
297            }
298        }
299    });
300
301    // LOAD TASKS
302
303    grunt.loadNpmTasks('grunt-amd-check');
304    grunt.loadNpmTasks('grunt-banner');
305    grunt.loadNpmTasks('grunt-coffeelint');
306    grunt.loadNpmTasks('grunt-contrib-clean');
307    grunt.loadNpmTasks('grunt-contrib-coffee');
308    grunt.loadNpmTasks('grunt-contrib-copy');
309    grunt.loadNpmTasks('grunt-contrib-jshint');
310    grunt.loadNpmTasks('grunt-contrib-less');
311    grunt.loadNpmTasks('grunt-contrib-watch');
312    grunt.loadNpmTasks('grunt-dojo');
313    grunt.loadNpmTasks('grunt-git-deploy');
314    grunt.loadNpmTasks('grunt-htmlhint');
315    grunt.loadNpmTasks('grunt-http');
316    grunt.loadNpmTasks('grunt-jsonlint');
317    grunt.loadNpmTasks('grunt-path-check');
318    grunt.loadNpmTasks('grunt-svninfo');
319    grunt.loadNpmTasks('grunt-tv4');
320    grunt.loadTasks('./grunt-tasks');
321
322    grunt.registerTask('print',"Print a variable.",
323                       function(varname,name) {
324                            grunt.log.write(grunt.template.process((name||varname)+"=<%= "+varname+" %>"));
325                       });
326
327    // UTIL FUNCTIONS
328
329    function dest(files) {
330        return _.chain(files)
331            .map(function(item){ return item.dest; })
332            .flatten()
333            .value();
334    }
335
336    function exclude(dest) {
337        return _.map(dest, function(dest){ return '!'+dest; });
338    }
339   
340};
Note: See TracBrowser for help on using the repository browser.