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.

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