You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1459 lines
43 KiB

9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /*
  2. All configurable options are defined in separate files inside the 'task/' folder
  3. Please adjust these files according to your personal requirements
  4. */
  5. /*******************************
  6. Set-up
  7. *******************************/
  8. var
  9. gulp = require('gulp-help')(require('gulp')),
  10. // node components & oddballs
  11. console = require('better-console'),
  12. del = require('del'),
  13. extend = require('extend'),
  14. fs = require('fs'),
  15. path = require('path'),
  16. runSequence = require('run-sequence'),
  17. wrench = require('wrench'),
  18. // gulp dependencies
  19. autoprefixer = require('gulp-autoprefixer'),
  20. chmod = require('gulp-chmod'),
  21. clone = require('gulp-clone'),
  22. concat = require('gulp-concat'),
  23. concatCSS = require('gulp-concat-css'),
  24. copy = require('gulp-copy'),
  25. debug = require('gulp-debug'),
  26. flatten = require('gulp-flatten'),
  27. header = require('gulp-header'),
  28. jeditor = require('gulp-json-editor'),
  29. karma = require('gulp-karma'),
  30. less = require('gulp-less'),
  31. minifyCSS = require('gulp-minify-css'),
  32. notify = require('gulp-notify'),
  33. plumber = require('gulp-plumber'),
  34. print = require('gulp-print'),
  35. prompt = require('gulp-prompt'),
  36. rename = require('gulp-rename'),
  37. replace = require('gulp-replace'),
  38. rtlcss = require('gulp-rtlcss'),
  39. sourcemaps = require('gulp-sourcemaps'),
  40. uglify = require('gulp-uglify'),
  41. util = require('gulp-util'),
  42. watch = require('gulp-watch'),
  43. // config
  44. banner = require('./tasks/banner'),
  45. comments = require('./tasks/comments'),
  46. defaults = require('./tasks/defaults'),
  47. log = require('./tasks/log'),
  48. questions = require('./tasks/questions'),
  49. settings = require('./tasks/gulp-settings'),
  50. // admin
  51. release = require('./tasks/admin/release'),
  52. git = require('gulp-git'),
  53. githubAPI = require('github'),
  54. oAuth = fs.existsSync('./tasks/admin/oauth.js')
  55. ? require('./tasks/admin/oauth')
  56. : false,
  57. github,
  58. // local
  59. runSetup = false,
  60. overwrite = true,
  61. config,
  62. package,
  63. github,
  64. version,
  65. // derived
  66. base,
  67. clean,
  68. output,
  69. source,
  70. assetPaths,
  71. componentGlob,
  72. // temporary
  73. folder
  74. ;
  75. /*******************************
  76. Read Settings
  77. *******************************/
  78. try {
  79. // try to load json
  80. var
  81. config = require(defaults.files.config),
  82. package = (fs.existsSync(defaults.files.npm))
  83. ? require(defaults.files.npm)
  84. : false
  85. ;
  86. }
  87. catch(error) {
  88. if(error.code === 'MODULE_NOT_FOUND') {
  89. console.error('No semantic.json config found');
  90. }
  91. var config = false;
  92. }
  93. /*******************************
  94. Values Derived From Config
  95. *******************************/
  96. var
  97. getConfigValues = function() {
  98. if(!config) {
  99. runSetup = true;
  100. config = defaults;
  101. }
  102. config = extend(true, {}, defaults, config);
  103. // shorthand
  104. base = config.base;
  105. clean = config.paths.clean;
  106. output = config.paths.output;
  107. source = config.paths.source;
  108. version = (package !== undefined)
  109. ? package.version || 'Unknown'
  110. : 'Unknown'
  111. ;
  112. // create glob for matching filenames from components in semantic.json
  113. componentGlob = (typeof config.components == 'object')
  114. ? (config.components.length > 1)
  115. ? '{' + config.components.join(',') + '}'
  116. : config.components[0]
  117. : '{' + defaults.components.join(',') + '}'
  118. ;
  119. // relative paths
  120. assetPaths = {
  121. uncompressed : path.relative(output.uncompressed, output.themes).replace(/\\/g,'/'),
  122. compressed : path.relative(output.compressed, output.themes).replace(/\\/g,'/'),
  123. packaged : path.relative(output.packaged, output.themes).replace(/\\/g,'/')
  124. };
  125. // add base to values
  126. for(var folder in source) {
  127. if(source.hasOwnProperty(folder)) {
  128. source[folder] = path.normalize(base + source[folder]);
  129. }
  130. }
  131. for(folder in output) {
  132. if(output.hasOwnProperty(folder)) {
  133. output[folder] = path.normalize(base + output[folder]);
  134. }
  135. }
  136. clean = base + clean;
  137. }
  138. ;
  139. getConfigValues();
  140. /*******************************
  141. Tasks
  142. *******************************/
  143. gulp.task('default', false, [
  144. 'check install'
  145. ]);
  146. gulp.task('watch', 'Watch for site/theme changes (Default Task)', function(callback) {
  147. console.clear();
  148. console.log('Watching source files for changes');
  149. if(!fs.existsSync(config.files.theme)) {
  150. console.error('Cant compile LESS. Run "gulp install" to create a theme config file');
  151. return;
  152. }
  153. if(config.rtl) {
  154. gulp.start('watch rtl');
  155. return;
  156. }
  157. // watching changes in style
  158. gulp
  159. .watch([
  160. source.config,
  161. source.definitions + '**/*.less',
  162. source.site + '**/*.{overrides,variables}',
  163. source.themes + '**/*.{overrides,variables}'
  164. ], function(file) {
  165. var
  166. srcPath,
  167. stream,
  168. compressedStream,
  169. uncompressedStream,
  170. isDefinition,
  171. isPackagedTheme,
  172. isSiteTheme,
  173. isConfig
  174. ;
  175. gulp.src(file.path)
  176. .pipe(print(log.modified))
  177. ;
  178. // recompile on *.override , *.variable change
  179. isDefinition = (file.path.indexOf(source.definitions) !== -1);
  180. isPackagedTheme = (file.path.indexOf(source.themes) !== -1);
  181. isSiteTheme = (file.path.indexOf(source.site) !== -1);
  182. isConfig = (file.path.indexOf('.config') !== -1);
  183. if(isDefinition || isPackagedTheme || isSiteTheme) {
  184. srcPath = util.replaceExtension(file.path, '.less');
  185. srcPath = srcPath.replace(config.regExp.themePath, source.definitions);
  186. srcPath = srcPath.replace(source.site, source.definitions);
  187. }
  188. else if(isConfig) {
  189. console.log('Change detected in theme config');
  190. gulp.start('build');
  191. }
  192. else {
  193. srcPath = util.replaceExtension(file.path, '.less');
  194. }
  195. // get relative asset path (path returns wrong path? hardcoded)
  196. // assetPaths.source = path.relative(srcPath, path.resolve(source.themes));
  197. assetPaths.source = '../../themes';
  198. if( fs.existsSync(srcPath) ) {
  199. // unified css stream
  200. stream = gulp.src(srcPath)
  201. .pipe(plumber())
  202. //.pipe(sourcemaps.init())
  203. .pipe(less(settings.less))
  204. .pipe(replace(comments.variables.in, comments.variables.out))
  205. .pipe(replace(comments.large.in, comments.large.out))
  206. .pipe(replace(comments.small.in, comments.small.out))
  207. .pipe(replace(comments.tiny.in, comments.tiny.out))
  208. .pipe(autoprefixer(settings.prefix))
  209. ;
  210. // use 2 concurrent streams from same source
  211. uncompressedStream = stream.pipe(clone());
  212. compressedStream = stream.pipe(clone());
  213. uncompressedStream
  214. .pipe(plumber())
  215. .pipe(replace(assetPaths.source, assetPaths.uncompressed))
  216. //.pipe(sourcemaps.write('/', settings.sourcemap))
  217. .pipe(header(banner, settings.header))
  218. .pipe(chmod(config.permission))
  219. .pipe(gulp.dest(output.uncompressed))
  220. .pipe(print(log.created))
  221. .on('end', function() {
  222. gulp.start('package uncompressed css');
  223. })
  224. ;
  225. compressedStream = stream
  226. .pipe(plumber())
  227. .pipe(clone())
  228. .pipe(replace(assetPaths.source, assetPaths.compressed))
  229. .pipe(minifyCSS(settings.minify))
  230. .pipe(rename(settings.rename.minCSS))
  231. //.pipe(sourcemaps.write('/', settings.sourcemap))
  232. .pipe(header(banner, settings.header))
  233. .pipe(chmod(config.permission))
  234. .pipe(gulp.dest(output.compressed))
  235. .pipe(print(log.created))
  236. .on('end', function() {
  237. gulp.start('package compressed css');
  238. })
  239. ;
  240. }
  241. else {
  242. console.log('SRC Path Does Not Exist', srcPath);
  243. }
  244. })
  245. ;
  246. // watch changes in assets
  247. gulp
  248. .watch([
  249. source.themes + '**/assets/**'
  250. ], function(file) {
  251. // copy assets
  252. gulp.src(file.path, { base: source.themes })
  253. .pipe(chmod(config.permission))
  254. .pipe(gulp.dest(output.themes))
  255. .pipe(print(log.created))
  256. ;
  257. })
  258. ;
  259. // watch changes in js
  260. gulp
  261. .watch([
  262. source.definitions + '**/*.js'
  263. ], function(file) {
  264. gulp.src(file.path)
  265. .pipe(plumber())
  266. .pipe(chmod(config.permission))
  267. .pipe(gulp.dest(output.uncompressed))
  268. .pipe(print(log.created))
  269. .pipe(sourcemaps.init())
  270. .pipe(uglify(settings.uglify))
  271. .pipe(rename(settings.rename.minJS))
  272. .pipe(chmod(config.permission))
  273. .pipe(gulp.dest(output.compressed))
  274. .pipe(print(log.created))
  275. .on('end', function() {
  276. gulp.start('package compressed js');
  277. gulp.start('package uncompressed js');
  278. })
  279. ;
  280. })
  281. ;
  282. });
  283. // Builds all files
  284. gulp.task('build', 'Builds all files from source', function(callback) {
  285. var
  286. stream,
  287. compressedStream,
  288. uncompressedStream
  289. ;
  290. console.info('Building Semantic');
  291. if(!fs.existsSync(config.files.theme)) {
  292. console.error('Cant build LESS. Run "gulp install" to create a theme config file');
  293. return;
  294. }
  295. if(config.rtl) {
  296. gulp.start('build rtl');
  297. return;
  298. }
  299. // get relative asset path (path returns wrong path?)
  300. // assetPaths.source = path.relative(srcPath, path.resolve(source.themes));
  301. assetPaths.source = '../../themes'; // hardcoded
  302. // copy assets
  303. gulp.src(source.themes + '**/assets/**')
  304. .pipe(chmod(config.permission))
  305. .pipe(gulp.dest(output.themes))
  306. ;
  307. // javascript stream
  308. gulp.src(source.definitions + '**/' + componentGlob + '.js')
  309. .pipe(plumber())
  310. .pipe(flatten())
  311. .pipe(chmod(config.permission))
  312. .pipe(gulp.dest(output.uncompressed))
  313. .pipe(print(log.created))
  314. // .pipe(sourcemaps.init())
  315. .pipe(uglify(settings.uglify))
  316. .pipe(rename(settings.rename.minJS))
  317. .pipe(header(banner, settings.header))
  318. .pipe(chmod(config.permission))
  319. .pipe(gulp.dest(output.compressed))
  320. .pipe(print(log.created))
  321. .on('end', function() {
  322. gulp.start('package compressed js');
  323. gulp.start('package uncompressed js');
  324. })
  325. ;
  326. // unified css stream
  327. stream = gulp.src(source.definitions + '**/' + componentGlob + '.less')
  328. .pipe(plumber())
  329. //.pipe(sourcemaps.init())
  330. .pipe(less(settings.less))
  331. .pipe(flatten())
  332. .pipe(replace(comments.variables.in, comments.variables.out))
  333. .pipe(replace(comments.large.in, comments.large.out))
  334. .pipe(replace(comments.small.in, comments.small.out))
  335. .pipe(replace(comments.tiny.in, comments.tiny.out))
  336. .pipe(autoprefixer(settings.prefix))
  337. ;
  338. // use 2 concurrent streams from same source to concat release
  339. uncompressedStream = stream.pipe(clone());
  340. compressedStream = stream.pipe(clone());
  341. uncompressedStream
  342. .pipe(plumber())
  343. .pipe(replace(assetPaths.source, assetPaths.uncompressed))
  344. //.pipe(sourcemaps.write('/', settings.sourcemap))
  345. .pipe(header(banner, settings.header))
  346. .pipe(chmod(config.permission))
  347. .pipe(gulp.dest(output.uncompressed))
  348. .pipe(print(log.created))
  349. .on('end', function() {
  350. gulp.start('package uncompressed css');
  351. })
  352. ;
  353. compressedStream = stream
  354. .pipe(plumber())
  355. .pipe(clone())
  356. .pipe(replace(assetPaths.source, assetPaths.compressed))
  357. .pipe(minifyCSS(settings.minify))
  358. .pipe(rename(settings.rename.minCSS))
  359. //.pipe(sourcemaps.write('/', settings.sourcemap))
  360. .pipe(header(banner, settings.header))
  361. .pipe(chmod(config.permission))
  362. .pipe(gulp.dest(output.compressed))
  363. .pipe(print(log.created))
  364. .on('end', function() {
  365. callback();
  366. gulp.start('package compressed css');
  367. })
  368. ;
  369. });
  370. // cleans distribution files
  371. gulp.task('clean', 'Clean dist folder', function(callback) {
  372. return del([clean], settings.del, callback);
  373. });
  374. gulp.task('version', 'Displays current version of Semantic', function(callback) {
  375. console.log('Semantic UI ' + version);
  376. });
  377. /*******************************
  378. RTL Tasks
  379. *******************************/
  380. /* Watch RTL */
  381. gulp.task('watch rtl', 'Watch for site/theme changes (Default Task)', function(callback) {
  382. console.clear();
  383. console.log('Watching RTL source files for changes');
  384. if(!fs.existsSync(config.files.theme)) {
  385. console.error('Cant compile LESS. Run "gulp install" to create a theme config file');
  386. return;
  387. }
  388. // watching changes in style
  389. gulp
  390. .watch([
  391. source.config,
  392. source.definitions + '**/*.less',
  393. source.site + '**/*.{overrides,variables}',
  394. source.themes + '**/*.{overrides,variables}'
  395. ], function(file) {
  396. var
  397. srcPath,
  398. stream,
  399. compressedStream,
  400. uncompressedStream,
  401. isDefinition,
  402. isPackagedTheme,
  403. isSiteTheme,
  404. isConfig
  405. ;
  406. gulp.src(file.path)
  407. .pipe(print(log.modified))
  408. ;
  409. // recompile on *.override , *.variable change
  410. isDefinition = (file.path.indexOf(source.definitions) !== -1);
  411. isPackagedTheme = (file.path.indexOf(source.themes) !== -1);
  412. isSiteTheme = (file.path.indexOf(source.site) !== -1);
  413. isConfig = (file.path.indexOf('.config') !== -1);
  414. if(isDefinition || isPackagedTheme || isSiteTheme) {
  415. srcPath = util.replaceExtension(file.path, '.less');
  416. srcPath = srcPath.replace(config.regExp.themePath, source.definitions);
  417. srcPath = srcPath.replace(source.site, source.definitions);
  418. }
  419. else if(isConfig) {
  420. console.log('Change detected in theme config');
  421. gulp.start('build');
  422. }
  423. else {
  424. srcPath = util.replaceExtension(file.path, '.less');
  425. }
  426. // get relative asset path (path returns wrong path? hardcoded)
  427. // assetPaths.source = path.relative(srcPath, path.resolve(source.themes));
  428. assetPaths.source = '../../themes';
  429. if( fs.existsSync(srcPath) ) {
  430. // unified css stream
  431. stream = gulp.src(srcPath)
  432. .pipe(plumber())
  433. //.pipe(sourcemaps.init())
  434. .pipe(less(settings.less))
  435. .pipe(replace(comments.variables.in, comments.variables.out))
  436. .pipe(replace(comments.large.in, comments.large.out))
  437. .pipe(replace(comments.small.in, comments.small.out))
  438. .pipe(replace(comments.tiny.in, comments.tiny.out))
  439. .pipe(autoprefixer(settings.prefix))
  440. .pipe(rtlcss())
  441. ;
  442. // use 2 concurrent streams from same source
  443. uncompressedStream = stream.pipe(clone());
  444. compressedStream = stream.pipe(clone());
  445. uncompressedStream
  446. .pipe(plumber())
  447. .pipe(replace(assetPaths.source, assetPaths.uncompressed))
  448. //.pipe(sourcemaps.write('/', settings.sourcemap))
  449. .pipe(header(banner, settings.header))
  450. .pipe(chmod(config.permission))
  451. .pipe(rename(settings.rename.rtlCSS))
  452. .pipe(gulp.dest(output.uncompressed))
  453. .pipe(print(log.created))
  454. .on('end', function() {
  455. gulp.start('package uncompressed rtl css');
  456. })
  457. ;
  458. compressedStream = stream
  459. .pipe(plumber())
  460. .pipe(clone())
  461. .pipe(replace(assetPaths.source, assetPaths.compressed))
  462. .pipe(minifyCSS(settings.minify))
  463. //.pipe(sourcemaps.write('/', settings.sourcemap))
  464. .pipe(header(banner, settings.header))
  465. .pipe(chmod(config.permission))
  466. .pipe(rename(settings.rename.rtlMinCSS))
  467. .pipe(gulp.dest(output.compressed))
  468. .pipe(print(log.created))
  469. .on('end', function() {
  470. gulp.start('package compressed rtl css');
  471. })
  472. ;
  473. }
  474. else {
  475. console.log('SRC Path Does Not Exist', srcPath);
  476. }
  477. })
  478. ;
  479. // watch changes in assets
  480. gulp
  481. .watch([
  482. source.themes + '**/assets/**'
  483. ], function(file) {
  484. // copy assets
  485. gulp.src(file.path, { base: source.themes })
  486. .pipe(chmod(config.permission))
  487. .pipe(gulp.dest(output.themes))
  488. .pipe(print(log.created))
  489. ;
  490. })
  491. ;
  492. // watch changes in js
  493. gulp
  494. .watch([
  495. source.definitions + '**/*.js'
  496. ], function(file) {
  497. gulp.src(file.path)
  498. .pipe(plumber())
  499. .pipe(chmod(config.permission))
  500. .pipe(gulp.dest(output.uncompressed))
  501. .pipe(print(log.created))
  502. .pipe(sourcemaps.init())
  503. .pipe(uglify(settings.uglify))
  504. .pipe(rename(settings.rename.minJS))
  505. .pipe(chmod(config.permission))
  506. .pipe(gulp.dest(output.compressed))
  507. .pipe(print(log.created))
  508. .on('end', function() {
  509. gulp.start('package compressed js');
  510. gulp.start('package uncompressed js');
  511. })
  512. ;
  513. })
  514. ;
  515. });
  516. /* Build RTL */
  517. gulp.task('build rtl', 'Builds all files from source', function(callback) {
  518. var
  519. stream,
  520. compressedStream,
  521. uncompressedStream
  522. ;
  523. console.info('Building Semantic RTL');
  524. if(!fs.existsSync(config.files.theme)) {
  525. console.error('Cant build LESS. Run "gulp install" to create a theme config file');
  526. return;
  527. }
  528. // get relative asset path (path returns wrong path?)
  529. // assetPaths.source = path.relative(srcPath, path.resolve(source.themes));
  530. assetPaths.source = '../../themes'; // hardcoded
  531. // copy assets
  532. gulp.src(source.themes + '**/assets/**')
  533. .pipe(chmod(config.permission))
  534. .pipe(gulp.dest(output.themes))
  535. ;
  536. // javascript stream
  537. gulp.src(source.definitions + '**/' + componentGlob + '.js')
  538. .pipe(plumber())
  539. .pipe(flatten())
  540. .pipe(chmod(config.permission))
  541. .pipe(gulp.dest(output.uncompressed))
  542. .pipe(print(log.created))
  543. // .pipe(sourcemaps.init())
  544. .pipe(uglify(settings.uglify))
  545. .pipe(rename(settings.rename.minJS))
  546. .pipe(header(banner, settings.header))
  547. .pipe(chmod(config.permission))
  548. .pipe(gulp.dest(output.compressed))
  549. .pipe(print(log.created))
  550. .on('end', function() {
  551. gulp.start('package compressed js');
  552. gulp.start('package uncompressed js');
  553. })
  554. ;
  555. // unified css stream
  556. stream = gulp.src(source.definitions + '**/' + componentGlob + '.less')
  557. .pipe(plumber())
  558. //.pipe(sourcemaps.init())
  559. .pipe(less(settings.less))
  560. .pipe(flatten())
  561. .pipe(replace(comments.variables.in, comments.variables.out))
  562. .pipe(replace(comments.large.in, comments.large.out))
  563. .pipe(replace(comments.small.in, comments.small.out))
  564. .pipe(replace(comments.tiny.in, comments.tiny.out))
  565. .pipe(autoprefixer(settings.prefix))
  566. .pipe(rtlcss())
  567. ;
  568. // use 2 concurrent streams from same source to concat release
  569. uncompressedStream = stream.pipe(clone());
  570. compressedStream = stream.pipe(clone());
  571. uncompressedStream
  572. .pipe(plumber())
  573. .pipe(replace(assetPaths.source, assetPaths.uncompressed))
  574. //.pipe(sourcemaps.write('/', settings.sourcemap))
  575. .pipe(rename(settings.rename.rtlCSS))
  576. .pipe(header(banner, settings.header))
  577. .pipe(chmod(config.permission))
  578. .pipe(gulp.dest(output.uncompressed))
  579. .pipe(print(log.created))
  580. .on('end', function() {
  581. gulp.start('package uncompressed rtl css');
  582. })
  583. ;
  584. compressedStream = stream
  585. .pipe(plumber())
  586. .pipe(clone())
  587. .pipe(replace(assetPaths.source, assetPaths.compressed))
  588. .pipe(minifyCSS(settings.minify))
  589. .pipe(rename(settings.rename.rtlMinCSS))
  590. //.pipe(sourcemaps.write('/', settings.sourcemap))
  591. .pipe(header(banner, settings.header))
  592. .pipe(chmod(config.permission))
  593. .pipe(gulp.dest(output.compressed))
  594. .pipe(print(log.created))
  595. .on('end', function() {
  596. callback();
  597. gulp.start('package compressed rtl css');
  598. })
  599. ;
  600. });
  601. gulp.task('package uncompressed rtl css', false, function () {
  602. return gulp.src(output.uncompressed + '**/' + componentGlob + '!(*.min|*.map).rtl.css')
  603. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  604. .pipe(concatCSS('semantic.rtl.css'))
  605. .pipe(gulp.dest(output.packaged))
  606. .pipe(print(log.created))
  607. ;
  608. });
  609. gulp.task('package compressed rtl css', false, function () {
  610. return gulp.src(output.uncompressed + '**/' + componentGlob + '!(*.min|*.map).rtl.css')
  611. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  612. .pipe(concatCSS('semantic.rtl.min.css'))
  613. .pipe(minifyCSS(settings.minify))
  614. .pipe(header(banner, settings.header))
  615. .pipe(gulp.dest(output.packaged))
  616. .pipe(print(log.created))
  617. ;
  618. });
  619. /*--------------
  620. Internal
  621. ---------------*/
  622. gulp.task('package uncompressed css', false, function() {
  623. return gulp.src(output.uncompressed + '**/' + componentGlob + config.ignoredFiles + '.css')
  624. .pipe(plumber())
  625. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  626. .pipe(concatCSS('semantic.css'))
  627. .pipe(chmod(config.permission))
  628. .pipe(gulp.dest(output.packaged))
  629. .pipe(print(log.created))
  630. ;
  631. });
  632. gulp.task('package compressed css', false, function() {
  633. return gulp.src(output.uncompressed + '**/' + componentGlob + config.ignoredFiles + '.css')
  634. .pipe(plumber())
  635. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  636. .pipe(concatCSS('semantic.min.css'))
  637. .pipe(minifyCSS(settings.minify))
  638. .pipe(header(banner, settings.header))
  639. .pipe(chmod(config.permission))
  640. .pipe(gulp.dest(output.packaged))
  641. .pipe(print(log.created))
  642. ;
  643. });
  644. gulp.task('package uncompressed js', false, function() {
  645. return gulp.src(output.uncompressed + '**/' + componentGlob + '!(*.min|*.map).js')
  646. .pipe(plumber())
  647. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  648. .pipe(concat('semantic.js'))
  649. .pipe(header(banner, settings.header))
  650. .pipe(chmod(config.permission))
  651. .pipe(gulp.dest(output.packaged))
  652. .pipe(print(log.created))
  653. ;
  654. });
  655. gulp.task('package compressed js', false, function() {
  656. return gulp.src(output.uncompressed + '**/' + componentGlob + '!(*.min|*.map).js')
  657. .pipe(plumber())
  658. .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  659. .pipe(concat('semantic.min.js'))
  660. .pipe(uglify(settings.uglify))
  661. .pipe(header(banner, settings.header))
  662. .pipe(chmod(config.permission))
  663. .pipe(gulp.dest(output.packaged))
  664. .pipe(print(log.created))
  665. ;
  666. });
  667. /*--------------
  668. Config
  669. ---------------*/
  670. gulp.task('check install', false, function () {
  671. setTimeout(function() {
  672. if( runSetup || !fs.existsSync(config.files.site)) {
  673. console.log('No semantic.json file found. Starting install...');
  674. gulp.start('install');
  675. }
  676. else {
  677. gulp.start('watch');
  678. }
  679. }, 50);
  680. });
  681. gulp.task('install', 'Set-up project for first time', function () {
  682. console.clear();
  683. gulp
  684. .src('gulpfile.js')
  685. .pipe(prompt.prompt(questions.setup, function(answers) {
  686. var
  687. siteVariable = /@siteFolder .*\'(.*)/mg,
  688. siteDestination = answers.site || config.folders.site,
  689. pathToSite = path.relative(path.resolve(config.folders.theme), path.resolve(siteDestination)).replace(/\\/g,'/'),
  690. sitePathReplace = "@siteFolder : '" + pathToSite + "/';",
  691. configExists = fs.existsSync(config.files.config),
  692. themeConfigExists = fs.existsSync(config.files.theme),
  693. siteExists = fs.existsSync(siteDestination),
  694. jsonSource = (configExists)
  695. ? config.files.config
  696. : config.templates.config,
  697. json = {
  698. paths: {
  699. source: {},
  700. output: {}
  701. }
  702. }
  703. ;
  704. // exit if config exists and user specifies no overwrite
  705. if(answers.overwrite !== undefined && answers.overwrite == 'no') {
  706. return;
  707. }
  708. console.clear();
  709. console.log('Installing');
  710. console.log('------------------------------');
  711. // create site files
  712. if(siteExists) {
  713. console.info('Site folder exists, merging files (no overwrite)', siteDestination);
  714. }
  715. else {
  716. console.info('Creating site theme folder', siteDestination);
  717. }
  718. // copy recursively without overwrite
  719. wrench.copyDirSyncRecursive(config.templates.site, siteDestination, settings.wrench.recursive);
  720. // adjust less variable for site folder location
  721. console.info('Adjusting @siteFolder', sitePathReplace);
  722. if(themeConfigExists) {
  723. gulp.src(config.files.site)
  724. .pipe(plumber())
  725. .pipe(replace(siteVariable, sitePathReplace))
  726. .pipe(chmod(config.permission))
  727. .pipe(gulp.dest(config.folders.theme))
  728. ;
  729. }
  730. else {
  731. console.info('Creating src/theme.config (LESS config)');
  732. gulp.src(config.templates.theme)
  733. .pipe(plumber())
  734. .pipe(rename({ extname : '' }))
  735. .pipe(replace(siteVariable, sitePathReplace))
  736. .pipe(chmod(config.permission))
  737. .pipe(gulp.dest(config.folders.theme))
  738. ;
  739. }
  740. // determine semantic.json config
  741. if(answers.components) {
  742. json.components = answers.components;
  743. }
  744. if(answers.permission) {
  745. json.permission = +answers.permission;
  746. }
  747. if(answers.dist) {
  748. answers.dist = answers.dist;
  749. json.paths.output = {
  750. packaged : answers.dist + '/',
  751. uncompressed : answers.dist + '/components/',
  752. compressed : answers.dist + '/components/',
  753. themes : answers.dist + '/themes/'
  754. };
  755. }
  756. if(answers.rtl) {
  757. json.rtl = (answers.rtl == 'yes')
  758. ? true
  759. : false
  760. ;
  761. }
  762. if(answers.site) {
  763. json.paths.source.site = answers.site + '/';
  764. }
  765. if(answers.packaged) {
  766. json.paths.output.packaged = answers.packaged + '/';
  767. }
  768. if(answers.compressed) {
  769. json.paths.output.compressed = answers.compressed + '/';
  770. }
  771. if(answers.uncompressed) {
  772. json.paths.output.uncompressed = answers.uncompressed + '/';
  773. }
  774. // write semantic.json
  775. if(configExists) {
  776. console.info('Extending semantic.json (Gulp config)');
  777. gulp.src(jsonSource)
  778. .pipe(plumber())
  779. .pipe(rename(settings.rename.json)) // preserve file extension
  780. .pipe(jeditor(json))
  781. .pipe(chmod(config.permission))
  782. .pipe(gulp.dest('./'))
  783. ;
  784. }
  785. else {
  786. console.info('Creating semantic.json (Gulp config)');
  787. gulp.src(jsonSource)
  788. .pipe(plumber())
  789. .pipe(rename({ extname : '' })) // remove .template from ext
  790. .pipe(jeditor(json))
  791. .pipe(chmod(config.permission))
  792. .pipe(gulp.dest('./'))
  793. ;
  794. }
  795. console.log('');
  796. console.log('');
  797. }))
  798. .pipe(prompt.prompt(questions.cleanup, function(answers) {
  799. if(answers.cleanup == 'yes') {
  800. del(config.setupFiles);
  801. }
  802. if(answers.build == 'yes') {
  803. config = require(config.files.config);
  804. getConfigValues();
  805. gulp.start('build');
  806. }
  807. }))
  808. ;
  809. });
  810. /*******************************
  811. Admin Tasks
  812. *******************************/
  813. var
  814. adminQuestions = require('./tasks/admin/questions'),
  815. newVersion = false
  816. ;
  817. /* Moves watched files to static site generator output */
  818. gulp.task('serve-docs', false, function () {
  819. config = require('./tasks/admin/docs.json');
  820. getConfigValues();
  821. // copy source files
  822. gulp
  823. .watch([
  824. 'src/**/*.*'
  825. ], function(file) {
  826. console.clear();
  827. return gulp.src(file.path, { base: 'src/' })
  828. .pipe(chmod(config.permission))
  829. .pipe(gulp.dest(output.less))
  830. .pipe(print(log.created))
  831. ;
  832. })
  833. ;
  834. gulp.start('watch');
  835. });
  836. /* Builds files to docs source */
  837. gulp.task('build-docs', false, function () {
  838. console.clear();
  839. // pushes to docpad files
  840. config = require('./tasks/admin/docs.json');
  841. getConfigValues();
  842. gulp.start('build');
  843. // copy source
  844. gulp.src('src/**/*.*')
  845. .pipe(chmod(config.permission))
  846. .pipe(gulp.dest(output.less))
  847. .pipe(print(log.created))
  848. ;
  849. });
  850. /* Release */
  851. gulp.task('release', false, function() {
  852. // gulp bump
  853. // Ask for release type (minor, major, patch)
  854. // Bump package.json
  855. // Bump composer.json
  856. if(!oAuth) {
  857. console.error('Must add node include tasks/admin/oauth.js with oauth token for GitHub');
  858. return;
  859. }
  860. github = new githubAPI({
  861. version : '3.0.0',
  862. debug : true,
  863. protocol : 'https',
  864. timeout : 5000
  865. });
  866. github.authenticate({
  867. type: 'oauth',
  868. token: oAuth.token
  869. });
  870. // gulp build
  871. //runSequence('update git');
  872. runSequence('build', 'create repos', 'update git');
  873. // #Create SCSS Version
  874. // #Create RTL Release
  875. });
  876. /* Build Component Release Only */
  877. gulp.task('build release', false, function() {
  878. runSequence('build', 'create repos');
  879. });
  880. /*--------------
  881. Internal
  882. ---------------*/
  883. gulp.task('create repos', false, function(callback) {
  884. var
  885. stream,
  886. index,
  887. tasks = []
  888. ;
  889. for(index in release.components) {
  890. var
  891. component = release.components[index]
  892. ;
  893. // streams... designed to save time and make coding fun...
  894. (function(component) {
  895. var
  896. outputDirectory = release.outputRoot + component,
  897. isJavascript = fs.existsSync(output.compressed + component + '.js'),
  898. isCSS = fs.existsSync(output.compressed + component + '.css'),
  899. capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
  900. packageName = release.packageRoot + component,
  901. repoName = release.repoRoot + capitalizedComponent,
  902. gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
  903. repoURL = 'https://github.com/' + release.org + '/' + repoName + '/',
  904. regExp = {
  905. match : {
  906. // readme
  907. name : '{component}',
  908. titleName : '{Component}',
  909. // release notes
  910. spacedVersions : /(###.*\n)\n+(?=###)/gm,
  911. spacedLists : /(^- .*\n)\n+(?=^-)/gm,
  912. trim : /^\s+|\s+$/g,
  913. unrelatedNotes : new RegExp('^((?!(^.*(' + component + ').*$|###.*)).)*$', 'gmi'),
  914. whitespace : /\n\s*\n\s*\n/gm,
  915. // npm
  916. export : /\$\.fn\.\w+\s*=\s*function\(parameters\)\s*{/g,
  917. formExport : /\$\.fn\.\w+\s*=\s*function\(fields, parameters\)\s*{/g,
  918. settingsExport : /\$\.fn\.\w+\.settings\s*=/g,
  919. settingsReference : /\$\.fn\.\w+\.settings/g,
  920. jQuery : /jQuery/g
  921. },
  922. replace : {
  923. // readme
  924. name : component,
  925. titleName : capitalizedComponent,
  926. // release notes
  927. spacedVersions : '',
  928. spacedLists : '$1',
  929. trim : '',
  930. unrelatedNotes : '',
  931. whitespace : '\n\n',
  932. // npm
  933. export : 'module.exports = function(parameters) {\n var _module = module;\n',
  934. formExport : 'module.exports = function(fields, parameters) {\n var _module = module;\n',
  935. settingsExport : 'module.exports.settings =',
  936. settingsReference : '_module.exports.settings',
  937. jQuery : 'require("jquery")'
  938. }
  939. },
  940. task = {
  941. all : component + ' creating',
  942. repo : component + ' create repo',
  943. bower : component + ' create bower.json',
  944. readme : component + ' create README',
  945. readme : component + ' create README',
  946. npm : component + ' create NPM Module',
  947. notes : component + ' create release notes',
  948. composer : component + ' create composer.json',
  949. package : component + ' create package.json'
  950. }
  951. ;
  952. // copy dist files into output folder adjusting asset paths
  953. gulp.task(task.repo, false, function() {
  954. return gulp.src(release.source + component + '.*')
  955. .pipe(plumber())
  956. .pipe(flatten())
  957. .pipe(replace(release.paths.source, release.paths.output))
  958. .pipe(chmod(config.permission))
  959. .pipe(gulp.dest(outputDirectory))
  960. ;
  961. });
  962. // create npm module
  963. gulp.task(task.npm, false, function() {
  964. return gulp.src(release.source + component + '!(*.min|*.map).js')
  965. .pipe(plumber())
  966. .pipe(flatten())
  967. .pipe(replace(regExp.match.export, regExp.replace.export))
  968. .pipe(replace(regExp.match.formExport, regExp.replace.formExport))
  969. .pipe(replace(regExp.match.settingsExport, regExp.replace.settingsExport))
  970. .pipe(replace(regExp.match.settingsReference, regExp.replace.settingsReference))
  971. .pipe(replace(regExp.match.jQuery, regExp.replace.jQuery))
  972. .pipe(rename('index.js'))
  973. .pipe(chmod(config.permission))
  974. .pipe(gulp.dest(outputDirectory))
  975. ;
  976. });
  977. // create readme
  978. gulp.task(task.readme, false, function() {
  979. return gulp.src(release.templates.readme)
  980. .pipe(plumber())
  981. .pipe(flatten())
  982. .pipe(replace(regExp.match.name, regExp.replace.name))
  983. .pipe(replace(regExp.match.titleName, regExp.replace.titleName))
  984. .pipe(chmod(config.permission))
  985. .pipe(gulp.dest(outputDirectory))
  986. ;
  987. });
  988. // extend bower.json
  989. gulp.task(task.bower, false, function() {
  990. return gulp.src(release.templates.bower)
  991. .pipe(plumber())
  992. .pipe(flatten())
  993. .pipe(jeditor(function(bower) {
  994. bower.name = packageName;
  995. bower.description = capitalizedComponent + ' - Semantic UI';
  996. if(isJavascript) {
  997. if(isCSS) {
  998. bower.main = [
  999. component + '.js',
  1000. component + '.css'
  1001. ];
  1002. }
  1003. else {
  1004. bower.main = [
  1005. component + '.js'
  1006. ];
  1007. }
  1008. bower.dependencies = {
  1009. jquery: '>=1.8'
  1010. };
  1011. }
  1012. else {
  1013. bower.main = [
  1014. component + '.css'
  1015. ];
  1016. }
  1017. return bower;
  1018. }))
  1019. .pipe(chmod(config.permission))
  1020. .pipe(gulp.dest(outputDirectory))
  1021. ;
  1022. });
  1023. // extend package.json
  1024. gulp.task(task.package, false, function() {
  1025. return gulp.src(release.templates.package)
  1026. .pipe(plumber())
  1027. .pipe(flatten())
  1028. .pipe(jeditor(function(package) {
  1029. if(isJavascript) {
  1030. package.dependencies = {
  1031. jquery: 'x.x.x'
  1032. };
  1033. package.main = 'index.js';
  1034. }
  1035. package.name = packageName;
  1036. if(version) {
  1037. package.version = version;
  1038. }
  1039. package.title = 'Semantic UI - ' + capitalizedComponent;
  1040. package.description = 'Single component release of ' + component;
  1041. package.repository = {
  1042. type : 'git',
  1043. url : gitURL
  1044. };
  1045. return package;
  1046. }))
  1047. .pipe(chmod(config.permission))
  1048. .pipe(gulp.dest(outputDirectory))
  1049. ;
  1050. });
  1051. // extend composer.json
  1052. gulp.task(task.composer, false, function() {
  1053. return gulp.src(release.templates.composer)
  1054. .pipe(plumber())
  1055. .pipe(flatten())
  1056. .pipe(jeditor(function(composer) {
  1057. if(isJavascript) {
  1058. composer.dependencies = {
  1059. jquery: 'x.x.x'
  1060. };
  1061. composer.main = component + '.js';
  1062. }
  1063. composer.name = 'semantic/' + component;
  1064. if(version) {
  1065. composer.version = version;
  1066. }
  1067. composer.description = 'Single component release of ' + component;
  1068. return composer;
  1069. }))
  1070. .pipe(chmod(config.permission))
  1071. .pipe(gulp.dest(outputDirectory))
  1072. ;
  1073. });
  1074. // create release notes
  1075. gulp.task(task.notes, false, function() {
  1076. return gulp.src(release.templates.notes)
  1077. .pipe(plumber())
  1078. .pipe(flatten())
  1079. // Remove release notes for lines not mentioning component
  1080. .pipe(replace(regExp.match.unrelatedNotes, regExp.replace.unrelatedNotes))
  1081. .pipe(replace(regExp.match.whitespace, regExp.replace.whitespace))
  1082. .pipe(replace(regExp.match.spacedVersions, regExp.replace.spacedVersions))
  1083. .pipe(replace(regExp.match.spacedLists, regExp.replace.spacedLists))
  1084. .pipe(replace(regExp.match.trim, regExp.replace.trim))
  1085. .pipe(chmod(config.permission))
  1086. .pipe(gulp.dest(outputDirectory))
  1087. ;
  1088. });
  1089. // synchronous tasks in orchestrator? I think not
  1090. gulp.task(task.all, false, function(callback) {
  1091. runSequence([
  1092. task.repo,
  1093. task.npm,
  1094. task.bower,
  1095. task.readme,
  1096. task.package,
  1097. task.composer,
  1098. task.notes
  1099. ], callback);
  1100. });
  1101. tasks.push(task.all);
  1102. })(component);
  1103. }
  1104. runSequence(tasks, callback);
  1105. });
  1106. gulp.task('register repos', false, function(callback) {
  1107. var
  1108. index = -1,
  1109. total = release.components.length,
  1110. process = require('child_process'),
  1111. stream,
  1112. stepRepo
  1113. ;
  1114. console.log('Registering repos with package managers');
  1115. // Do Git commands synchronously per component, to avoid issues
  1116. stepRepo = function() {
  1117. index = index + 1;
  1118. if(index >= total) {
  1119. return;
  1120. }
  1121. var
  1122. component = release.components[index],
  1123. outputDirectory = release.outputRoot + component + '/',
  1124. capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
  1125. packageName = release.packageRoot + component,
  1126. repoName = release.repoRoot + capitalizedComponent,
  1127. gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
  1128. exec = process.exec,
  1129. execSettings = {cwd: outputDirectory},
  1130. registerBower = 'bower register ' + packageName + ' ' + gitURL,
  1131. registerNPM = 'npm publish'
  1132. ;
  1133. /* One time register
  1134. exec(registerBower, execSettings, function(err, stdout, stderr) {
  1135. stepRepo();
  1136. });
  1137. */
  1138. /* Update npm
  1139. exec(registerNPM, execSettings, function(err, stdout, stderr) {
  1140. console.log(err, stdout, stderr);
  1141. stepRepo();
  1142. });
  1143. */
  1144. }
  1145. stepRepo();
  1146. });
  1147. gulp.task('update git', false, function() {
  1148. var
  1149. index = -1,
  1150. total = release.components.length,
  1151. stream,
  1152. stepRepo
  1153. ;
  1154. console.log('Handling git');
  1155. // Do Git commands synchronously per component, to avoid issues
  1156. stepRepo = function() {
  1157. index = index + 1;
  1158. if(index >= total) {
  1159. return;
  1160. }
  1161. var
  1162. component = release.components[index],
  1163. outputDirectory = release.outputRoot + component + '/',
  1164. capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
  1165. repoName = release.repoRoot + capitalizedComponent,
  1166. gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
  1167. repoURL = 'https://github.com/' + release.org + '/' + repoName + '/',
  1168. gitOptions = { cwd: outputDirectory },
  1169. quietOptions = { args: '-q', cwd: outputDirectory },
  1170. isRepository = fs.existsSync(outputDirectory + '.git/')
  1171. componentPackage = fs.existsSync(outputDirectory + 'package.json' )
  1172. ? require(outputDirectory + 'package.json')
  1173. : false,
  1174. commitArgs = (oAuth.name !== undefined && oAuth.email !== undefined)
  1175. ? '--author "' + oAuth.name + ' <' + oAuth.email + '>"'
  1176. : '',
  1177. isNewVersion = (version && componentPackage.version != version),
  1178. mergeMessage = 'Merged from upstream',
  1179. commitMessage = (isNewVersion)
  1180. ? 'Updated component to version ' + version
  1181. : 'Updated component release from Semantic-UI (Automatic)'
  1182. ;
  1183. console.log('Processing repository:' + outputDirectory);
  1184. if(isRepository) {
  1185. commitFiles();
  1186. }
  1187. else {
  1188. createRepo();
  1189. }
  1190. // standard path
  1191. function commitFiles() {
  1192. // commit files
  1193. console.log('Committing files', commitArgs);
  1194. gulp.src('**/*', gitOptions)
  1195. .pipe(git.add(gitOptions))
  1196. .pipe(git.commit(commitMessage, { args: commitArgs, cwd: outputDirectory }))
  1197. .on('error', function(error) {
  1198. console.log('Nothing new to commit');
  1199. stepRepo();
  1200. })
  1201. .on('finish', function(callback) {
  1202. pullFiles();
  1203. })
  1204. ;
  1205. }
  1206. function pullFiles() {
  1207. console.log('Pulling files');
  1208. git.pull('origin', 'master', { args: '', cwd: outputDirectory }, function(error) {
  1209. if(error && error.message.search("Couldn't find remote ref") != -1) {
  1210. createRepo();
  1211. }
  1212. else {
  1213. console.log('Pull completed successfully');
  1214. mergeCommit();
  1215. }
  1216. });
  1217. };
  1218. function mergeCommit() {
  1219. // commit files
  1220. console.log('Adding merge commit', commitArgs);
  1221. gulp.src('', gitOptions)
  1222. .pipe(git.add(gitOptions))
  1223. .pipe(git.commit(mergeMessage, { args: commitArgs, cwd: outputDirectory }))
  1224. .on('error', function(error) {
  1225. console.log('Nothing new to merge', error);
  1226. })
  1227. .on('finish', function(callback) {
  1228. if(1) {
  1229. tagFiles();
  1230. }
  1231. else {
  1232. pushFiles();
  1233. }
  1234. })
  1235. ;
  1236. }
  1237. function tagFiles() {
  1238. console.log('Tagging new version ', version);
  1239. git.tag(version, 'Updated version from semantic-ui (automatic)', function (err) {
  1240. pushFiles();
  1241. });
  1242. }
  1243. function pushFiles() {
  1244. console.log('Pushing files');
  1245. git.push('origin', 'master', { args: '', cwd: outputDirectory }, function(error) {
  1246. if(error && error.message.search("Couldn't find remote ref") == -1) {
  1247. createRepo();
  1248. }
  1249. console.log('Push completed successfully');
  1250. stepRepo();
  1251. });
  1252. };
  1253. // set-up path
  1254. function createRepo() {
  1255. console.log('Creating repository ' + repoURL);
  1256. github.repos.createFromOrg({
  1257. org : release.org,
  1258. name : repoName,
  1259. homepage : release.homepage
  1260. }, function() {
  1261. if(isRepository) {
  1262. addRemote();
  1263. }
  1264. else {
  1265. initRepo();
  1266. }
  1267. });
  1268. }
  1269. function initRepo() {
  1270. console.log('Initializing repository in ' + outputDirectory);
  1271. git.init(gitOptions, function(error) {
  1272. if(error) {
  1273. console.error('Error initializing repo');
  1274. return;
  1275. }
  1276. addRemote();
  1277. });
  1278. }
  1279. function addRemote() {
  1280. console.log('Adding remote origin as ' + gitURL);
  1281. git.addRemote('origin', gitURL, gitOptions, firstPushFiles);
  1282. }
  1283. function firstPushFiles() {
  1284. console.log('Pushing files');
  1285. git.push('origin', 'master', { args: '-u', cwd: outputDirectory }, function(error) {
  1286. if(error) {
  1287. console.log(error);
  1288. pullFiles();
  1289. }
  1290. else {
  1291. console.log('First push completed successfully');
  1292. stepRepo();
  1293. }
  1294. });
  1295. };
  1296. };
  1297. return stepRepo();
  1298. });