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.

1450 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.dist) {
  745. answers.dist = answers.dist;
  746. json.paths.output = {
  747. packaged : answers.dist + '/',
  748. uncompressed : answers.dist + '/components/',
  749. compressed : answers.dist + '/components/',
  750. themes : answers.dist + '/themes/'
  751. };
  752. }
  753. if(answers.site) {
  754. json.paths.source.site = answers.site + '/';
  755. }
  756. if(answers.packaged) {
  757. json.paths.output.packaged = answers.packaged + '/';
  758. }
  759. if(answers.compressed) {
  760. json.paths.output.compressed = answers.compressed + '/';
  761. }
  762. if(answers.uncompressed) {
  763. json.paths.output.uncompressed = answers.uncompressed + '/';
  764. }
  765. // write semantic.json
  766. if(configExists) {
  767. console.info('Extending semantic.json (Gulp config)');
  768. gulp.src(jsonSource)
  769. .pipe(plumber())
  770. .pipe(rename(settings.rename.json)) // preserve file extension
  771. .pipe(jeditor(json))
  772. .pipe(chmod(config.permission))
  773. .pipe(gulp.dest('./'))
  774. ;
  775. }
  776. else {
  777. console.info('Creating semantic.json (Gulp config)');
  778. gulp.src(jsonSource)
  779. .pipe(plumber())
  780. .pipe(rename({ extname : '' })) // remove .template from ext
  781. .pipe(jeditor(json))
  782. .pipe(chmod(config.permission))
  783. .pipe(gulp.dest('./'))
  784. ;
  785. }
  786. console.log('');
  787. console.log('');
  788. }))
  789. .pipe(prompt.prompt(questions.cleanup, function(answers) {
  790. if(answers.cleanup == 'yes') {
  791. del(config.setupFiles);
  792. }
  793. if(answers.build == 'yes') {
  794. config = require(config.files.config);
  795. getConfigValues();
  796. gulp.start('build');
  797. }
  798. }))
  799. ;
  800. });
  801. /*******************************
  802. Admin Tasks
  803. *******************************/
  804. var
  805. adminQuestions = require('./tasks/admin/questions'),
  806. newVersion = false
  807. ;
  808. /* Moves watched files to static site generator output */
  809. gulp.task('serve-docs', false, function () {
  810. config = require('./tasks/admin/docs.json');
  811. getConfigValues();
  812. // copy source files
  813. gulp
  814. .watch([
  815. 'src/**/*.*'
  816. ], function(file) {
  817. console.clear();
  818. return gulp.src(file.path, { base: 'src/' })
  819. .pipe(chmod(config.permission))
  820. .pipe(gulp.dest(output.less))
  821. .pipe(print(log.created))
  822. ;
  823. })
  824. ;
  825. gulp.start('watch');
  826. });
  827. /* Builds files to docs source */
  828. gulp.task('build-docs', false, function () {
  829. console.clear();
  830. // pushes to docpad files
  831. config = require('./tasks/admin/docs.json');
  832. getConfigValues();
  833. gulp.start('build');
  834. // copy source
  835. gulp.src('src/**/*.*')
  836. .pipe(chmod(config.permission))
  837. .pipe(gulp.dest(output.less))
  838. .pipe(print(log.created))
  839. ;
  840. });
  841. /* Release */
  842. gulp.task('release', false, function() {
  843. // gulp bump
  844. // Ask for release type (minor, major, patch)
  845. // Bump package.json
  846. // Bump composer.json
  847. if(!oAuth) {
  848. console.error('Must add node include tasks/admin/oauth.js with oauth token for GitHub');
  849. return;
  850. }
  851. github = new githubAPI({
  852. version : '3.0.0',
  853. debug : true,
  854. protocol : 'https',
  855. timeout : 5000
  856. });
  857. github.authenticate({
  858. type: 'oauth',
  859. token: oAuth.token
  860. });
  861. // gulp build
  862. //runSequence('update git');
  863. runSequence('build', 'create repos', 'update git');
  864. // #Create SCSS Version
  865. // #Create RTL Release
  866. });
  867. /* Build Component Release Only */
  868. gulp.task('build release', false, function() {
  869. runSequence('build', 'create repos');
  870. });
  871. /*--------------
  872. Internal
  873. ---------------*/
  874. gulp.task('create repos', false, function(callback) {
  875. var
  876. stream,
  877. index,
  878. tasks = []
  879. ;
  880. for(index in release.components) {
  881. var
  882. component = release.components[index]
  883. ;
  884. // streams... designed to save time and make coding fun...
  885. (function(component) {
  886. var
  887. outputDirectory = release.outputRoot + component,
  888. isJavascript = fs.existsSync(output.compressed + component + '.js'),
  889. isCSS = fs.existsSync(output.compressed + component + '.css'),
  890. capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
  891. packageName = release.packageRoot + component,
  892. repoName = release.repoRoot + capitalizedComponent,
  893. gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
  894. repoURL = 'https://github.com/' + release.org + '/' + repoName + '/',
  895. regExp = {
  896. match : {
  897. // readme
  898. name : '{component}',
  899. titleName : '{Component}',
  900. // release notes
  901. spacedVersions : /(###.*\n)\n+(?=###)/gm,
  902. spacedLists : /(^- .*\n)\n+(?=^-)/gm,
  903. trim : /^\s+|\s+$/g,
  904. unrelatedNotes : new RegExp('^((?!(^.*(' + component + ').*$|###.*)).)*$', 'gmi'),
  905. whitespace : /\n\s*\n\s*\n/gm,
  906. // npm
  907. export : /\$\.fn\.\w+\s*=\s*function\(parameters\)\s*{/g,
  908. formExport : /\$\.fn\.\w+\s*=\s*function\(fields, parameters\)\s*{/g,
  909. settingsExport : /\$\.fn\.\w+\.settings\s*=/g,
  910. settingsReference : /\$\.fn\.\w+\.settings/g,
  911. jQuery : /jQuery/g
  912. },
  913. replace : {
  914. // readme
  915. name : component,
  916. titleName : capitalizedComponent,
  917. // release notes
  918. spacedVersions : '',
  919. spacedLists : '$1',
  920. trim : '',
  921. unrelatedNotes : '',
  922. whitespace : '\n\n',
  923. // npm
  924. export : 'module.exports = function(parameters) {\n var _module = module;\n',
  925. formExport : 'module.exports = function(fields, parameters) {\n var _module = module;\n',
  926. settingsExport : 'module.exports.settings =',
  927. settingsReference : '_module.exports.settings',
  928. jQuery : 'require("jquery")'
  929. }
  930. },
  931. task = {
  932. all : component + ' creating',
  933. repo : component + ' create repo',
  934. bower : component + ' create bower.json',
  935. readme : component + ' create README',
  936. readme : component + ' create README',
  937. npm : component + ' create NPM Module',
  938. notes : component + ' create release notes',
  939. composer : component + ' create composer.json',
  940. package : component + ' create package.json'
  941. }
  942. ;
  943. // copy dist files into output folder adjusting asset paths
  944. gulp.task(task.repo, false, function() {
  945. return gulp.src(release.source + component + '.*')
  946. .pipe(plumber())
  947. .pipe(flatten())
  948. .pipe(replace(release.paths.source, release.paths.output))
  949. .pipe(chmod(config.permission))
  950. .pipe(gulp.dest(outputDirectory))
  951. ;
  952. });
  953. // create npm module
  954. gulp.task(task.npm, false, function() {
  955. return gulp.src(release.source + component + '!(*.min|*.map).js')
  956. .pipe(plumber())
  957. .pipe(flatten())
  958. .pipe(replace(regExp.match.export, regExp.replace.export))
  959. .pipe(replace(regExp.match.formExport, regExp.replace.formExport))
  960. .pipe(replace(regExp.match.settingsExport, regExp.replace.settingsExport))
  961. .pipe(replace(regExp.match.settingsReference, regExp.replace.settingsReference))
  962. .pipe(replace(regExp.match.jQuery, regExp.replace.jQuery))
  963. .pipe(rename('index.js'))
  964. .pipe(chmod(config.permission))
  965. .pipe(gulp.dest(outputDirectory))
  966. ;
  967. });
  968. // create readme
  969. gulp.task(task.readme, false, function() {
  970. return gulp.src(release.templates.readme)
  971. .pipe(plumber())
  972. .pipe(flatten())
  973. .pipe(replace(regExp.match.name, regExp.replace.name))
  974. .pipe(replace(regExp.match.titleName, regExp.replace.titleName))
  975. .pipe(chmod(config.permission))
  976. .pipe(gulp.dest(outputDirectory))
  977. ;
  978. });
  979. // extend bower.json
  980. gulp.task(task.bower, false, function() {
  981. return gulp.src(release.templates.bower)
  982. .pipe(plumber())
  983. .pipe(flatten())
  984. .pipe(jeditor(function(bower) {
  985. bower.name = packageName;
  986. bower.description = capitalizedComponent + ' - Semantic UI';
  987. if(isJavascript) {
  988. if(isCSS) {
  989. bower.main = [
  990. component + '.js',
  991. component + '.css'
  992. ];
  993. }
  994. else {
  995. bower.main = [
  996. component + '.js'
  997. ];
  998. }
  999. bower.dependencies = {
  1000. jquery: '>=1.8'
  1001. };
  1002. }
  1003. else {
  1004. bower.main = [
  1005. component + '.css'
  1006. ];
  1007. }
  1008. return bower;
  1009. }))
  1010. .pipe(chmod(config.permission))
  1011. .pipe(gulp.dest(outputDirectory))
  1012. ;
  1013. });
  1014. // extend package.json
  1015. gulp.task(task.package, false, function() {
  1016. return gulp.src(release.templates.package)
  1017. .pipe(plumber())
  1018. .pipe(flatten())
  1019. .pipe(jeditor(function(package) {
  1020. if(isJavascript) {
  1021. package.dependencies = {
  1022. jquery: 'x.x.x'
  1023. };
  1024. package.main = 'index.js';
  1025. }
  1026. package.name = packageName;
  1027. if(version) {
  1028. package.version = version;
  1029. }
  1030. package.title = 'Semantic UI - ' + capitalizedComponent;
  1031. package.description = 'Single component release of ' + component;
  1032. package.repository = {
  1033. type : 'git',
  1034. url : gitURL
  1035. };
  1036. return package;
  1037. }))
  1038. .pipe(chmod(config.permission))
  1039. .pipe(gulp.dest(outputDirectory))
  1040. ;
  1041. });
  1042. // extend composer.json
  1043. gulp.task(task.composer, false, function() {
  1044. return gulp.src(release.templates.composer)
  1045. .pipe(plumber())
  1046. .pipe(flatten())
  1047. .pipe(jeditor(function(composer) {
  1048. if(isJavascript) {
  1049. composer.dependencies = {
  1050. jquery: 'x.x.x'
  1051. };
  1052. composer.main = component + '.js';
  1053. }
  1054. composer.name = 'semantic/' + component;
  1055. if(version) {
  1056. composer.version = version;
  1057. }
  1058. composer.description = 'Single component release of ' + component;
  1059. return composer;
  1060. }))
  1061. .pipe(chmod(config.permission))
  1062. .pipe(gulp.dest(outputDirectory))
  1063. ;
  1064. });
  1065. // create release notes
  1066. gulp.task(task.notes, false, function() {
  1067. return gulp.src(release.templates.notes)
  1068. .pipe(plumber())
  1069. .pipe(flatten())
  1070. // Remove release notes for lines not mentioning component
  1071. .pipe(replace(regExp.match.unrelatedNotes, regExp.replace.unrelatedNotes))
  1072. .pipe(replace(regExp.match.whitespace, regExp.replace.whitespace))
  1073. .pipe(replace(regExp.match.spacedVersions, regExp.replace.spacedVersions))
  1074. .pipe(replace(regExp.match.spacedLists, regExp.replace.spacedLists))
  1075. .pipe(replace(regExp.match.trim, regExp.replace.trim))
  1076. .pipe(chmod(config.permission))
  1077. .pipe(gulp.dest(outputDirectory))
  1078. ;
  1079. });
  1080. // synchronous tasks in orchestrator? I think not
  1081. gulp.task(task.all, false, function(callback) {
  1082. runSequence([
  1083. task.repo,
  1084. task.npm,
  1085. task.bower,
  1086. task.readme,
  1087. task.package,
  1088. task.composer,
  1089. task.notes
  1090. ], callback);
  1091. });
  1092. tasks.push(task.all);
  1093. })(component);
  1094. }
  1095. runSequence(tasks, callback);
  1096. });
  1097. gulp.task('register repos', false, function(callback) {
  1098. var
  1099. index = -1,
  1100. total = release.components.length,
  1101. process = require('child_process'),
  1102. stream,
  1103. stepRepo
  1104. ;
  1105. console.log('Registering repos with package managers');
  1106. // Do Git commands synchronously per component, to avoid issues
  1107. stepRepo = function() {
  1108. index = index + 1;
  1109. if(index >= total) {
  1110. return;
  1111. }
  1112. var
  1113. component = release.components[index],
  1114. outputDirectory = release.outputRoot + component + '/',
  1115. capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
  1116. packageName = release.packageRoot + component,
  1117. repoName = release.repoRoot + capitalizedComponent,
  1118. gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
  1119. exec = process.exec,
  1120. execSettings = {cwd: outputDirectory},
  1121. registerBower = 'bower register ' + packageName + ' ' + gitURL,
  1122. registerNPM = 'npm publish'
  1123. ;
  1124. /* One time register
  1125. exec(registerBower, execSettings, function(err, stdout, stderr) {
  1126. stepRepo();
  1127. });
  1128. */
  1129. /* Update npm
  1130. exec(registerNPM, execSettings, function(err, stdout, stderr) {
  1131. console.log(err, stdout, stderr);
  1132. stepRepo();
  1133. });
  1134. */
  1135. }
  1136. stepRepo();
  1137. });
  1138. gulp.task('update git', false, function() {
  1139. var
  1140. index = -1,
  1141. total = release.components.length,
  1142. stream,
  1143. stepRepo
  1144. ;
  1145. console.log('Handling git');
  1146. // Do Git commands synchronously per component, to avoid issues
  1147. stepRepo = function() {
  1148. index = index + 1;
  1149. if(index >= total) {
  1150. return;
  1151. }
  1152. var
  1153. component = release.components[index],
  1154. outputDirectory = release.outputRoot + component + '/',
  1155. capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
  1156. repoName = release.repoRoot + capitalizedComponent,
  1157. gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
  1158. repoURL = 'https://github.com/' + release.org + '/' + repoName + '/',
  1159. gitOptions = { cwd: outputDirectory },
  1160. quietOptions = { args: '-q', cwd: outputDirectory },
  1161. isRepository = fs.existsSync(outputDirectory + '.git/')
  1162. componentPackage = fs.existsSync(outputDirectory + 'package.json' )
  1163. ? require(outputDirectory + 'package.json')
  1164. : false,
  1165. commitArgs = (oAuth.name !== undefined && oAuth.email !== undefined)
  1166. ? '--author "' + oAuth.name + ' <' + oAuth.email + '>"'
  1167. : '',
  1168. isNewVersion = (version && componentPackage.version != version),
  1169. mergeMessage = 'Merged from upstream',
  1170. commitMessage = (isNewVersion)
  1171. ? 'Updated component to version ' + version
  1172. : 'Updated component release from Semantic-UI (Automatic)'
  1173. ;
  1174. console.log('Processing repository:' + outputDirectory);
  1175. if(isRepository) {
  1176. commitFiles();
  1177. }
  1178. else {
  1179. createRepo();
  1180. }
  1181. // standard path
  1182. function commitFiles() {
  1183. // commit files
  1184. console.log('Committing files', commitArgs);
  1185. gulp.src('**/*', gitOptions)
  1186. .pipe(git.add(gitOptions))
  1187. .pipe(git.commit(commitMessage, { args: commitArgs, cwd: outputDirectory }))
  1188. .on('error', function(error) {
  1189. console.log('Nothing new to commit');
  1190. stepRepo();
  1191. })
  1192. .on('finish', function(callback) {
  1193. pullFiles();
  1194. })
  1195. ;
  1196. }
  1197. function pullFiles() {
  1198. console.log('Pulling files');
  1199. git.pull('origin', 'master', { args: '', cwd: outputDirectory }, function(error) {
  1200. if(error && error.message.search("Couldn't find remote ref") != -1) {
  1201. createRepo();
  1202. }
  1203. else {
  1204. console.log('Pull completed successfully');
  1205. mergeCommit();
  1206. }
  1207. });
  1208. };
  1209. function mergeCommit() {
  1210. // commit files
  1211. console.log('Adding merge commit', commitArgs);
  1212. gulp.src('', gitOptions)
  1213. .pipe(git.add(gitOptions))
  1214. .pipe(git.commit(mergeMessage, { args: commitArgs, cwd: outputDirectory }))
  1215. .on('error', function(error) {
  1216. console.log('Nothing new to merge', error);
  1217. })
  1218. .on('finish', function(callback) {
  1219. if(1) {
  1220. tagFiles();
  1221. }
  1222. else {
  1223. pushFiles();
  1224. }
  1225. })
  1226. ;
  1227. }
  1228. function tagFiles() {
  1229. console.log('Tagging new version ', version);
  1230. git.tag(version, 'Updated version from semantic-ui (automatic)', function (err) {
  1231. pushFiles();
  1232. });
  1233. }
  1234. function pushFiles() {
  1235. console.log('Pushing files');
  1236. git.push('origin', 'master', { args: '', cwd: outputDirectory }, function(error) {
  1237. if(error && error.message.search("Couldn't find remote ref") == -1) {
  1238. createRepo();
  1239. }
  1240. console.log('Push completed successfully');
  1241. stepRepo();
  1242. });
  1243. };
  1244. // set-up path
  1245. function createRepo() {
  1246. console.log('Creating repository ' + repoURL);
  1247. github.repos.createFromOrg({
  1248. org : release.org,
  1249. name : repoName,
  1250. homepage : release.homepage
  1251. }, function() {
  1252. if(isRepository) {
  1253. addRemote();
  1254. }
  1255. else {
  1256. initRepo();
  1257. }
  1258. });
  1259. }
  1260. function initRepo() {
  1261. console.log('Initializing repository in ' + outputDirectory);
  1262. git.init(gitOptions, function(error) {
  1263. if(error) {
  1264. console.error('Error initializing repo');
  1265. return;
  1266. }
  1267. addRemote();
  1268. });
  1269. }
  1270. function addRemote() {
  1271. console.log('Adding remote origin as ' + gitURL);
  1272. git.addRemote('origin', gitURL, gitOptions, firstPushFiles);
  1273. }
  1274. function firstPushFiles() {
  1275. console.log('Pushing files');
  1276. git.push('origin', 'master', { args: '-u', cwd: outputDirectory }, function(error) {
  1277. if(error) {
  1278. console.log(error);
  1279. pullFiles();
  1280. }
  1281. else {
  1282. console.log('First push completed successfully');
  1283. stepRepo();
  1284. }
  1285. });
  1286. };
  1287. };
  1288. return stepRepo();
  1289. });