Gruntfile.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. module.exports = function(grunt) {
  2. // Load all grunt modules
  3. require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
  4. // Tell our Express server that Grunt launched it
  5. process.env.GRUNTED = true;
  6. // Project configuration.
  7. grunt.initConfig({
  8. pkg: grunt.file.readJSON('package.json'),
  9. settings: grunt.file.readJSON('./server_config/settings.json'),
  10. font: {
  11. icons: {
  12. src: ['front/src/fonts/svg-icons/*.svg'],
  13. destCss: 'front/src/less/icons.less',
  14. destFonts: 'front/src/fonts/icons.woff',
  15. // Optional: Custom routing of font filepaths for CSS
  16. cssRouter: function (fontpath) {
  17. var pathArray = fontpath.split('/');
  18. var fileName = pathArray[pathArray.length - 1];
  19. return '/fonts/' + fileName;
  20. }
  21. }
  22. },
  23. less: {
  24. all: {
  25. files: [
  26. {
  27. expand: true,
  28. cwd: 'front/src/less/',
  29. src: ['**/*.less'],
  30. dest: 'front/src/css/',
  31. ext: '.css'
  32. }
  33. ]
  34. }
  35. },
  36. replace: {
  37. dist: {
  38. options: {
  39. patterns: [
  40. {
  41. match: 'googleAnalyticsId',
  42. replacement: '<%= settings.googleAnalyticsId %>'
  43. },
  44. {
  45. match: 'version',
  46. replacement: 'v<%= pkg.version %>'
  47. }
  48. ]
  49. },
  50. files: [
  51. {expand: true, flatten: true, src: ['front/src/main.html'], dest: 'front/build/'}
  52. ]
  53. }
  54. },
  55. jshint: {
  56. all: [
  57. '*.js',
  58. 'app/lib/*.js',
  59. 'bin/*.js',
  60. 'lib/**/*.js',
  61. 'app/nodeControllers/*.js',
  62. 'app/public/scripts/*.js',
  63. 'phantomas_custom/**/*.js',
  64. 'test/api/*.js',
  65. 'test/core/*.js',
  66. 'test/fixtures/*.js',
  67. 'front/src/js/**/*.js'
  68. ]
  69. },
  70. clean: {
  71. tmp: {
  72. src: ['.tmp']
  73. },
  74. dev: {
  75. src: ['front/src/css']
  76. },
  77. coverage: {
  78. src: ['.tmp', 'coverage/']
  79. },
  80. build: {
  81. src: ['front/build']
  82. }
  83. },
  84. copy: {
  85. beforeCoverage: {
  86. files: [
  87. {src: ['bin/server.js'], dest: '.tmp/'}
  88. ]
  89. },
  90. coverage: {
  91. files: [
  92. {src: ['test/**'], dest: 'coverage/'},
  93. {src: ['lib/metadata/**'], dest: 'coverage/'},
  94. {src: ['node_modules/phantomas/**'], dest: 'coverage/'},
  95. {src: ['lib/tools/phantomas/custom_modules/**'], dest: 'coverage/'}
  96. ]
  97. },
  98. build: {
  99. files: [
  100. {src: ['./front/src/fonts/icons.woff'], dest: './front/build/fonts/icons.woff'},
  101. {src: ['./front/src/img/favicon.png'], dest: './front/build/img/favicon.png'},
  102. {src: ['./front/src/img/logo-large.png'], dest: './front/build/img/logo-large.png'},
  103. ]
  104. }
  105. },
  106. lineremover: {
  107. beforeCoverage: {
  108. files: {
  109. '.tmp/bin/cli.js': 'bin/cli.js'
  110. },
  111. options: {
  112. exclusionPattern: /#!\/usr\/bin\/env node/
  113. }
  114. }
  115. },
  116. blanket: {
  117. coverageApp: {
  118. src: ['app/'],
  119. dest: 'coverage/app/'
  120. },
  121. coverageLib: {
  122. src: ['lib/'],
  123. dest: 'coverage/lib/'
  124. },
  125. coverageBin: {
  126. src: ['.tmp/bin/'],
  127. dest: 'coverage/bin/'
  128. }
  129. },
  130. mochaTest: {
  131. test: {
  132. options: {
  133. reporter: 'spec',
  134. },
  135. src: ['coverage/test/core/*.js', 'coverage/test/api/*.js']
  136. },
  137. 'test-current-work': {
  138. options: {
  139. reporter: 'spec',
  140. },
  141. src: ['test/core/offendersHelpersTest.js']
  142. },
  143. coverage: {
  144. options: {
  145. reporter: 'html-cov',
  146. quiet: true,
  147. captureFile: 'coverage/coverage.html'
  148. },
  149. src: ['coverage/test/core/*.js', 'coverage/test/api/*.js']
  150. }
  151. },
  152. env: {
  153. dev: {
  154. NODE_ENV: 'development'
  155. },
  156. built: {
  157. NODE_ENV: 'production'
  158. }
  159. },
  160. express: {
  161. dev: {
  162. options: {
  163. port: 8383,
  164. server: './bin/server.js',
  165. serverreload: true,
  166. showStack: true
  167. }
  168. },
  169. built: {
  170. options: {
  171. port: 8383,
  172. server: './bin/server.js',
  173. serverreload: true,
  174. showStack: true
  175. }
  176. },
  177. test: {
  178. options: {
  179. port: 8387,
  180. server: './coverage/bin/server.js',
  181. showStack: true
  182. }
  183. },
  184. 'test-current-work': {
  185. options: {
  186. port: 8387,
  187. server: './bin/server.js',
  188. showStack: true
  189. }
  190. },
  191. testSuite: {
  192. options: {
  193. port: 8388,
  194. bases: 'test/www'
  195. }
  196. }
  197. },
  198. useminPrepare: {
  199. html: './front/src/main.html',
  200. options: {
  201. dest: './front/build',
  202. root: ['./', './front/src']
  203. }
  204. },
  205. usemin: {
  206. html: './front/build/main.html',
  207. css: './front/build/css/*.css',
  208. options: {
  209. assetsDirs: ['front/build'],
  210. patterns: {
  211. css: [[/(\/fonts\/icons\.woff)/gm, 'Replacing reference to icons.woff']]
  212. }
  213. }
  214. },
  215. htmlmin: {
  216. options: {
  217. removeComments: true,
  218. collapseWhitespace: true,
  219. conservativeCollapse: true
  220. },
  221. main: {
  222. files: [{
  223. expand: true,
  224. cwd: './front/build/',
  225. src: 'main.html',
  226. flatten: true,
  227. dest: './front/build'
  228. }]
  229. },
  230. views: {
  231. files: [{
  232. expand: true,
  233. cwd: './front/src/views',
  234. src: '*.html',
  235. flatten: true,
  236. dest: '.tmp/views/'
  237. }]
  238. }
  239. },
  240. inline_angular_templates: {
  241. build: {
  242. options: {
  243. base: '.tmp',
  244. method: 'append'
  245. },
  246. files: {
  247. './front/build/main.html': ['.tmp/views/*.html']
  248. }
  249. }
  250. },
  251. filerev: {
  252. options: {
  253. algorithm: 'md5',
  254. length: 8
  255. },
  256. assets: {
  257. src: './front/build/*/*.*'
  258. }
  259. }
  260. });
  261. // Custom task: copies the test settings.json file to the coverage folder, and checks if there's no missing fields
  262. grunt.registerTask('copy-test-server-settings', function() {
  263. var mainSettingsFile = './server_config/settings.json';
  264. var testSettingsFile = './test/fixtures/settings.json';
  265. var mainSettings = grunt.file.readJSON(mainSettingsFile);
  266. var testSettings = grunt.file.readJSON(testSettingsFile);
  267. // Recursively compare keys of two objects (not the values)
  268. function compareKeys(original, copy, context) {
  269. for (var key in original) {
  270. if (!copy[key] && copy[key] !== '' && copy[key] !== 0) {
  271. grunt.fail.warn('Settings file ' + testSettingsFile + ' doesn\'t contain key ' + context + '.' + key);
  272. }
  273. if (original[key] !== null && typeof original[key] === 'object') {
  274. compareKeys(original[key], copy[key], context + '.' + key);
  275. }
  276. }
  277. }
  278. compareKeys(mainSettings, testSettings, 'settings');
  279. var outputFile = './coverage/server_config/settings.json';
  280. grunt.file.write(outputFile, JSON.stringify(testSettings, null, 4));
  281. grunt.log.ok('File ' + outputFile + ' created');
  282. });
  283. grunt.registerTask('icons', [
  284. 'font:icons',
  285. 'less',
  286. 'clean:tmp'
  287. ]);
  288. grunt.registerTask('build', [
  289. 'jshint',
  290. 'clean:build',
  291. 'copy:build',
  292. 'less',
  293. 'useminPrepare',
  294. 'concat',
  295. 'uglify',
  296. 'cssmin',
  297. 'replace',
  298. 'htmlmin:views',
  299. 'inline_angular_templates',
  300. 'filerev',
  301. 'usemin',
  302. 'htmlmin:main',
  303. 'clean:tmp'
  304. ]);
  305. grunt.registerTask('hint', [
  306. 'jshint'
  307. ]);
  308. grunt.registerTask('dev', [
  309. 'env:dev',
  310. 'express:dev'
  311. ]);
  312. grunt.registerTask('built', [
  313. 'env:built',
  314. 'express:built'
  315. ]);
  316. grunt.registerTask('test', [
  317. 'build',
  318. 'express:testSuite',
  319. 'clean:coverage',
  320. 'copy-test-server-settings',
  321. 'lineremover:beforeCoverage',
  322. 'copy:beforeCoverage',
  323. 'blanket',
  324. 'copy:coverage',
  325. 'express:test',
  326. 'mochaTest:test',
  327. 'mochaTest:coverage',
  328. 'clean:tmp'
  329. ]);
  330. grunt.registerTask('test-current-work', [
  331. 'jshint',
  332. 'express:testSuite',
  333. 'clean:coverage',
  334. 'copy-test-server-settings',
  335. 'express:test-current-work',
  336. 'mochaTest:test-current-work',
  337. 'clean:tmp'
  338. ]);
  339. };