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.

1131 lines
33 KiB

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