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.

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