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.

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