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.

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