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.

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