/*

All configurable options are defined in separate files inside the 'task/' folder
Please adjust these files according to your personal requirements

*/

/*******************************

Set-up

*******************************/

var

gulp         = require('gulp-help')(require('gulp')),

// node components & oddballs
console      = require('better-console'),
del          = require('del'),
extend       = require('extend'),
fs           = require('fs'),
path         = require('path'),
runSequence  = require('run-sequence'),
wrench       = require('wrench'),

// gulp dependencies
autoprefixer = require('gulp-autoprefixer'),
clone        = require('gulp-clone'),
concat       = require('gulp-concat'),
concatCSS    = require('gulp-concat-css'),
copy         = require('gulp-copy'),
debug        = require('gulp-debug'),
flatten      = require('gulp-flatten'),
header       = require('gulp-header'),
jeditor      = require('gulp-json-editor'),
karma        = require('gulp-karma'),
less         = require('gulp-less'),
minifyCSS    = require('gulp-minify-css'),
notify       = require('gulp-notify'),
plumber      = require('gulp-plumber'),
print        = require('gulp-print'),
prompt       = require('gulp-prompt'),
rename       = require('gulp-rename'),
replace      = require('gulp-replace'),
sourcemaps   = require('gulp-sourcemaps'),
uglify       = require('gulp-uglify'),
util         = require('gulp-util'),
watch        = require('gulp-watch'),

// config
banner       = require('./tasks/banner'),
comments     = require('./tasks/comments'),
defaults     = require('./tasks/defaults'),
log          = require('./tasks/log'),
questions    = require('./tasks/questions'),
settings     = require('./tasks/gulp-settings'),

// admin
release      = require('./tasks/admin/release'),
git          = require('gulp-git'),
githubAPI    = require('github'),

oAuth        = fs.existsSync('./tasks/admin/oauth.js')
  ? require('./tasks/admin/oauth')
  : false,
github,

// local
runSetup   = false,
overwrite  = true,
config,
package,
github,

version,

// derived
base,
clean,
output,
source,
assetPaths,
componentGlob,

// temporary
folder

;

/*******************************

Read Settings

*******************************/

try {

// try to load json
var
  config  = require(defaults.files.config),
  package = (fs.existsSync(defaults.files.npm))
    ? require(defaults.files.npm)
    : false
;

} catch(error) {

if(error.code === 'MODULE_NOT_FOUND') {
  console.error('No semantic.json config found');
}
var config = false;

}

/*******************************

Values Derived From Config

*******************************/

var

getConfigValues = function() {

  if(!config) {
    runSetup = true;
    config = defaults;
  }
  config = extend(true, {}, defaults, config);

  // shorthand
  base    = config.base;
  clean   = config.paths.clean;
  output  = config.paths.output;
  source  = config.paths.source;

  version = (package !== undefined)
    ? package.version || 'Unknown'
    : 'Unknown'
  ;

  // create glob for matching filenames from components in semantic.json
  componentGlob = (typeof config.components == 'object')
    ? (config.components.length > 1)
      ? '{' + config.components.join(',') + '}'
      : config.components[0]
    : '{' + defaults.components.join(',') + '}'
  ;

  // relative paths
  assetPaths = {
    uncompressed : path.relative(output.uncompressed, output.themes),
    compressed   : path.relative(output.compressed, output.themes),
    packaged     : path.relative(output.packaged, output.themes)
  };

  // add base to values
  for(var folder in source) {
    if(source.hasOwnProperty(folder)) {
      source[folder] = path.normalize(base + source[folder]);
    }
  }
  for(folder in output) {
    if(output.hasOwnProperty(folder)) {
      output[folder] = path.normalize(base + output[folder]);
    }
  }
  clean = base + clean;
}

;

getConfigValues();

/*******************************

Tasks

*******************************/

gulp.task(‘default’, false, [

'check install'

]);

gulp.task(‘watch’, ‘Watch for site/theme changes (Default Task)’, function(callback) {

console.clear();
console.log('Watching source files for changes');

if(!fs.existsSync(config.files.theme)) {
  console.error('Cant compile LESS. Run "gulp install" to create a theme config file');
  return;
}

// watching changes in style
gulp
  .watch([
    source.config,
    source.definitions   + '**/*.less',
    source.site          + '**/*.{overrides,variables}',
    source.themes        + '**/*.{overrides,variables}'
  ], function(file) {
    var
      srcPath,
      stream,
      compressedStream,
      uncompressedStream,
      isDefinition,
      isPackagedTheme,
      isSiteTheme,
      isConfig
    ;

    gulp.src(file.path)
      .pipe(print(log.modified))
    ;

    // recompile on *.override , *.variable change
    isDefinition    = (file.path.indexOf(source.definitions) !== -1);
    isPackagedTheme = (file.path.indexOf(source.themes) !== -1);
    isSiteTheme     = (file.path.indexOf(source.site) !== -1);
    isConfig        = (file.path.indexOf('.config') !== -1);

    if(isDefinition || isPackagedTheme || isSiteTheme) {
      srcPath = util.replaceExtension(file.path, '.less');
      srcPath = srcPath.replace(config.regExp.themePath, source.definitions);
      srcPath = srcPath.replace(source.site, source.definitions);
    }
    else if(isConfig) {
      console.log('Change detected in theme config');
      gulp.start('build');
    }
    else {
      srcPath = util.replaceExtension(file.path, '.less');
    }

    // get relative asset path (path returns wrong path? hardcoded)
    // assetPaths.source = path.relative(srcPath, path.resolve(source.themes));
    assetPaths.source = '../../themes';

    if( fs.existsSync(srcPath) ) {

      // unified css stream
      stream = gulp.src(srcPath)
        .pipe(plumber())
        //.pipe(sourcemaps.init())
        .pipe(less(settings.less))
        .pipe(replace(comments.variables.in, comments.variables.out))
        .pipe(replace(comments.large.in, comments.large.out))
        .pipe(replace(comments.small.in, comments.small.out))
        .pipe(replace(comments.tiny.in, comments.tiny.out))
        .pipe(autoprefixer(settings.prefix))
      ;

      // use 2 concurrent streams from same source
      uncompressedStream = stream.pipe(clone());
      compressedStream   = stream.pipe(clone());

      uncompressedStream
        .pipe(plumber())
        .pipe(replace(assetPaths.source, assetPaths.uncompressed))
        //.pipe(sourcemaps.write('/', settings.sourcemap))
        .pipe(header(banner, settings.header))
        .pipe(gulp.dest(output.uncompressed))
        .pipe(print(log.created))
        .on('end', function() {
          gulp.start('package uncompressed css');
        })
      ;

      compressedStream = stream
        .pipe(plumber())
        .pipe(clone())
        .pipe(replace(assetPaths.source, assetPaths.compressed))
        .pipe(minifyCSS(settings.minify))
        .pipe(rename(settings.rename.minCSS))
        //.pipe(sourcemaps.write('/', settings.sourcemap))
        .pipe(header(banner, settings.header))
        .pipe(gulp.dest(output.compressed))
        .pipe(print(log.created))
        .on('end', function() {
          gulp.start('package compressed css');
        })
      ;

    }
    else {
      console.log('SRC Path Does Not Exist', srcPath);
    }
  })
;

// watch changes in assets
gulp
  .watch([
    source.themes   + '**/assets/**'
  ], function(file) {
    // copy assets
    gulp.src(file.path, { base: source.themes })
      .pipe(gulp.dest(output.themes))
      .pipe(print(log.created))
    ;
  })
;

// watch changes in js
gulp
  .watch([
    source.definitions   + '**/*.js'
  ], function(file) {
    gulp.src(file.path)
      .pipe(plumber())
      .pipe(gulp.dest(output.uncompressed))
      .pipe(print(log.created))
      .pipe(sourcemaps.init())
      .pipe(uglify(settings.uglify))
      .pipe(rename(settings.rename.minJS))
      .pipe(gulp.dest(output.compressed))
      .pipe(print(log.created))
      .on('end', function() {
        gulp.start('package compressed js');
        gulp.start('package uncompressed js');
      })
    ;
  })
;

});

// Builds all files gulp.task(‘build’, ‘Builds all files from source’, function(callback) {

var
  stream,
  compressedStream,
  uncompressedStream
;

console.info('Building Semantic');

if(!fs.existsSync(config.files.theme)) {
  console.error('Cant build LESS. Run "gulp install" to create a theme config file');
  return;
}

// get relative asset path (path returns wrong path?)
// assetPaths.source = path.relative(srcPath, path.resolve(source.themes));
assetPaths.source = '../../themes'; // hardcoded

// copy assets
gulp.src(source.themes + '**/assets/**')
  .pipe(gulp.dest(output.themes))
;

// javascript stream

gulp.src(source.definitions + '**/' + componentGlob + '.js')
  .pipe(plumber())
  .pipe(flatten())
  .pipe(gulp.dest(output.uncompressed))
  .pipe(print(log.created))
  // .pipe(sourcemaps.init())
  .pipe(uglify(settings.uglify))
  .pipe(rename(settings.rename.minJS))
  .pipe(header(banner, settings.header))
  .pipe(gulp.dest(output.compressed))
  .pipe(print(log.created))
  .on('end', function() {
    gulp.start('package compressed js');
    gulp.start('package uncompressed js');
  })
;

// unified css stream
stream = gulp.src(source.definitions + '**/' + componentGlob + '.less')
  .pipe(plumber())
  //.pipe(sourcemaps.init())
  .pipe(less(settings.less))
  .pipe(flatten())
  .pipe(replace(comments.variables.in, comments.variables.out))
  .pipe(replace(comments.large.in, comments.large.out))
  .pipe(replace(comments.small.in, comments.small.out))
  .pipe(replace(comments.tiny.in, comments.tiny.out))
  .pipe(autoprefixer(settings.prefix))
;

// use 2 concurrent streams from same source to concat release
uncompressedStream = stream.pipe(clone());
compressedStream   = stream.pipe(clone());

uncompressedStream
  .pipe(plumber())
  .pipe(replace(assetPaths.source, assetPaths.uncompressed))
  //.pipe(sourcemaps.write('/', settings.sourcemap))
  .pipe(header(banner, settings.header))
  .pipe(gulp.dest(output.uncompressed))
  .pipe(print(log.created))
  .on('end', function() {
    gulp.start('package uncompressed css');
  })
;

compressedStream = stream
  .pipe(plumber())
  .pipe(clone())
  .pipe(replace(assetPaths.source, assetPaths.compressed))
  .pipe(minifyCSS(settings.minify))
  .pipe(rename(settings.rename.minCSS))
  //.pipe(sourcemaps.write('/', settings.sourcemap))
  .pipe(header(banner, settings.header))
  .pipe(gulp.dest(output.compressed))
  .pipe(print(log.created))
  .on('end', function() {
    callback();
    gulp.start('package compressed css');
  })
;

});

// cleans distribution files gulp.task(‘clean’, ‘Clean dist folder’, function(callback) {

return del([clean], settings.del, callback);

});

gulp.task(‘version’, ‘Displays current version of Semantic’, function(callback) {

console.log('Semantic UI ' + version);

});

/*————–

Internal

—————*/

gulp.task(‘package uncompressed css’, false, function() {

return gulp.src(output.uncompressed + '**/' + componentGlob + '!(*.min|*.map).css')
  .pipe(plumber())
  .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  .pipe(concatCSS('semantic.css'))
    .pipe(gulp.dest(output.packaged))
    .pipe(print(log.created))
;

});

gulp.task(‘package compressed css’, false, function() {

return gulp.src(output.uncompressed + '**/' + componentGlob + '!(*.min|*.map).css')
  .pipe(plumber())
  .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  .pipe(concatCSS('semantic.min.css'))
    .pipe(minifyCSS(settings.minify))
    .pipe(header(banner, settings.header))
    .pipe(gulp.dest(output.packaged))
    .pipe(print(log.created))
;

});

gulp.task(‘package uncompressed js’, false, function() {

return gulp.src(output.uncompressed + '**/' + componentGlob + '!(*.min|*.map).js')
  .pipe(plumber())
  .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  .pipe(concat('semantic.js'))
    .pipe(header(banner, settings.header))
    .pipe(gulp.dest(output.packaged))
    .pipe(print(log.created))
;

});

gulp.task(‘package compressed js’, false, function() {

return gulp.src(output.uncompressed + '**/' + componentGlob + '!(*.min|*.map).js')
  .pipe(plumber())
  .pipe(replace(assetPaths.uncompressed, assetPaths.packaged))
  .pipe(concat('semantic.min.js'))
    .pipe(uglify(settings.uglify))
    .pipe(header(banner, settings.header))
    .pipe(gulp.dest(output.packaged))
    .pipe(print(log.created))
;

});

/*————–

Config

—————*/

gulp.task(‘check install’, false, function () {

setTimeout(function() {
  if( runSetup || !fs.existsSync(config.files.site)) {
    console.log('No semantic.json file found. Starting install...');
    gulp.start('install');
  }
  else {
    gulp.start('watch');
  }
}, 50);

});

gulp.task(‘install’, ‘Set-up project for first time’, function () {

console.clear();
gulp
  .src('gulpfile.js')
  .pipe(prompt.prompt(questions.setup, function(answers) {
    var
      siteVariable      = /@siteFolder .*\'(.*)/mg,
      siteDestination   = answers.site || config.folders.site,

      pathToSite        = path.relative(path.resolve(config.folders.theme), path.resolve(siteDestination)),
      sitePathReplace   = "@siteFolder   : '" + pathToSite + "/';",

      configExists      = fs.existsSync(config.files.config),
      themeConfigExists = fs.existsSync(config.files.theme),
      siteExists        = fs.existsSync(siteDestination),

      jsonSource        = (configExists)
        ? config.files.config
        : config.templates.config,
      json = {
        paths: {
          source: {},
          output: {}
        }
      }
    ;

    // exit if config exists and user specifies no overwrite
    if(answers.overwrite !== undefined && answers.overwrite == 'no') {
      return;
    }

    console.clear();
    console.log('Installing');
    console.log('------------------------------');

    // create site files
    if(siteExists) {
      console.info('Site folder exists, merging files (no overwrite)', siteDestination);
    }
    else {
      console.info('Creating site theme folder', siteDestination);
    }
    // copy recursively without overwrite
    wrench.copyDirSyncRecursive(config.templates.site, siteDestination, settings.wrench.recursive);

    // adjust less variable for site folder location
    console.info('Adjusting @siteFolder', sitePathReplace);
    if(themeConfigExists) {
      gulp.src(config.files.site)
        .pipe(plumber())
        .pipe(replace(siteVariable, sitePathReplace))
        .pipe(gulp.dest(config.folders.theme))
      ;
    }
    else {
      console.info('Creating src/theme.config (LESS config)');
      gulp.src(config.templates.theme)
        .pipe(plumber())
        .pipe(rename({ extname : '' }))
        .pipe(replace(siteVariable, sitePathReplace))
        .pipe(gulp.dest(config.folders.theme))
      ;
    }

    // determine semantic.json config
    if(answers.components) {
      json.components = answers.components;
    }
    if(answers.dist) {
      answers.dist = answers.dist;
      json.paths.output = {
        packaged     : answers.dist + '/',
        uncompressed : answers.dist + '/components/',
        compressed   : answers.dist + '/components/',
        themes       : answers.dist + '/themes/'
      };
    }
    if(answers.site) {
      json.paths.source.site = answers.site + '/';
    }
    if(answers.packaged) {
      json.paths.output.packaged = answers.packaged + '/';
    }
    if(answers.compressed) {
      json.paths.output.compressed = answers.compressed + '/';
    }
    if(answers.uncompressed) {
      json.paths.output.uncompressed = answers.uncompressed + '/';
    }

    // write semantic.json
    if(configExists) {
      console.info('Extending semantic.json (Gulp config)');
      gulp.src(jsonSource)
        .pipe(plumber())
        .pipe(rename(settings.rename.json)) // preserve file extension
        .pipe(jeditor(json))
        .pipe(gulp.dest('./'))
      ;
    }
    else {
      console.info('Creating semantic.json (Gulp config)');
      gulp.src(jsonSource)
        .pipe(plumber())
        .pipe(rename({ extname : '' })) // remove .template from ext
        .pipe(jeditor(json))
        .pipe(gulp.dest('./'))
      ;
    }
    console.log('');
    console.log('');
  }))
  .pipe(prompt.prompt(questions.cleanup, function(answers) {
    if(answers.cleanup == 'yes') {
      del(config.setupFiles);
    }
    if(answers.build == 'yes') {
      config = require(config.files.config);
      getConfigValues();
      gulp.start('build');
    }
  }))
;

});

/*******************************

Admin Tasks

*******************************/

var

adminQuestions = require('./tasks/admin/questions'),
newVersion = false

;

/* Moves watched files to static site generator output */ gulp.task(‘serve-docs’, false, function () {

config = require('./tasks/admin/docs.json');
getConfigValues();

// copy source files
gulp
  .watch([
    'src/**/*.*'
  ], function(file) {
    console.clear();
    return gulp.src(file.path, { base: 'src/' })
      .pipe(gulp.dest(output.less))
      .pipe(print(log.created))
    ;
  })
;
gulp.start('watch');

});

/* Builds files to docs source */ gulp.task(‘build-docs’, false, function () {

console.clear();
// pushes to docpad files
config = require('./tasks/admin/docs.json');
getConfigValues();
gulp.start('build');

// copy source
gulp.src('src/**/*.*')
  .pipe(gulp.dest(output.less))
  .pipe(print(log.created))
;

});

/* Release */ gulp.task(‘release’, false, function() {

// gulp bump
// Ask for release type (minor, major, patch)
// Bump package.json
// Bump composer.json
if(!oAuth) {
  console.error('Must add node include tasks/admin/oauth.js with oauth token for GitHub');
  return;
}

github = new githubAPI({
  version    : '3.0.0',
  debug      : true,
  protocol   : 'https',
  timeout    : 5000
});

github.authenticate({
  type: 'oauth',
  token: oAuth.token
});

// gulp build
//runSequence('update git');
runSequence('build', 'create repos', 'update git');

// #Create SCSS Version
// #Create RTL Release

});

/* Build Component Release Only */ gulp.task(‘build release’, false, function() {

runSequence('build', 'create repos');

});

/*————–

Internal

—————*/

gulp.task(‘create repos’, false, function(callback) {

var
  stream,
  index,
  tasks = []
;

for(index in release.components) {

  var
    component            = release.components[index]
  ;

  // streams... designed to save time and make coding fun...
  (function(component) {

    var
      outputDirectory      = release.outputRoot + component,
      isJavascript         = fs.existsSync(output.compressed + component + '.js'),
      isCSS                = fs.existsSync(output.compressed + component + '.css'),
      capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
      packageName          = release.packageRoot + component,
      repoName             = release.repoRoot + capitalizedComponent,
      gitURL               = 'https://github.com/' + release.org + '/' + repoName + '.git',
      repoURL              = 'https://github.com/' + release.org + '/' + repoName + '/',
      regExp               = {
        match            : {
          // readme
          name              : '{component}',
          titleName         : '{Component}',
          // release notes
          spacedVersions    : /(###.*\n)\n+(?=###)/gm,
          spacedLists       : /(^- .*\n)\n+(?=^-)/gm,
          trim              : /^\s+|\s+$/g,
          unrelatedNotes    : new RegExp('^((?!(^.*(' + component + ').*$|###.*)).)*$', 'gmi'),
          whitespace        : /\n\s*\n\s*\n/gm,
          // npm
          export            : /\$\.fn\.\w+\s*=\s*function\(parameters\)\s*{/g,
          formExport        : /\$\.fn\.\w+\s*=\s*function\(fields, parameters\)\s*{/g,
          settingsExport    : /\$\.fn\.\w+\.settings\s*=/g,
          settingsReference : /\$\.fn\.\w+\.settings/g,
          jQuery            : /jQuery/g
        },
        replace : {
          // readme
          name              : component,
          titleName         : capitalizedComponent,
          // release notes
          spacedVersions    : '',
          spacedLists       : '$1',
          trim              : '',
          unrelatedNotes    : '',
          whitespace        : '\n\n',
          // npm
          export            :  'module.exports = function(parameters) {\n  var _module = module;\n',
          formExport        :  'module.exports = function(fields, parameters) {\n  var _module = module;\n',
          settingsExport    :  'module.exports.settings =',
          settingsReference :  '_module.exports.settings',
          jQuery            :  'require("jquery")'
        }
      },
      task = {
        all      : component + ' creating',
        repo     : component + ' create repo',
        bower    : component + ' create bower.json',
        readme   : component + ' create README',
        readme   : component + ' create README',
        npm      : component + ' create NPM Module',
        notes    : component + ' create release notes',
        composer : component + ' create composer.json',
        package  : component + ' create package.json'
      }
    ;

    // copy dist files into output folder adjusting asset paths
    gulp.task(task.repo, false, function() {
      return gulp.src(release.source + component + '.*')
        .pipe(plumber())
        .pipe(flatten())
        .pipe(replace(release.paths.source, release.paths.output))
        .pipe(gulp.dest(outputDirectory))
      ;
    });

    // create npm module
    gulp.task(task.npm, false, function() {
      return gulp.src(release.source + component + '!(*.min|*.map).js')
        .pipe(plumber())
        .pipe(flatten())
        .pipe(replace(regExp.match.export, regExp.replace.export))
        .pipe(replace(regExp.match.formExport, regExp.replace.formExport))
        .pipe(replace(regExp.match.settingsExport, regExp.replace.settingsExport))
        .pipe(replace(regExp.match.settingsReference, regExp.replace.settingsReference))
        .pipe(replace(regExp.match.jQuery, regExp.replace.jQuery))
        .pipe(rename('index.js'))
        .pipe(gulp.dest(outputDirectory))
      ;
    });

    // create readme
    gulp.task(task.readme, false, function() {
      return gulp.src(release.templates.readme)
        .pipe(plumber())
        .pipe(flatten())
        .pipe(replace(regExp.match.name, regExp.replace.name))
        .pipe(replace(regExp.match.titleName, regExp.replace.titleName))
        .pipe(gulp.dest(outputDirectory))
      ;
    });

    // extend bower.json
    gulp.task(task.bower, false, function() {
      return gulp.src(release.templates.bower)
        .pipe(plumber())
        .pipe(flatten())
        .pipe(jeditor(function(bower) {
          bower.name = packageName;
          bower.description = capitalizedComponent + ' - Semantic UI';
          if(isJavascript) {
            if(isCSS) {
              bower.main = [
                component + '.js',
                component + '.css'
              ];
            }
            else {
              bower.main = [
                component + '.js'
              ];
            }
            bower.dependencies = {
              jquery: '>=1.8'
            };
          }
          else {
            bower.main = [
              component + '.css'
            ];
          }
          return bower;
        }))
        .pipe(gulp.dest(outputDirectory))
      ;
    });

    // extend package.json
    gulp.task(task.package, false, function() {
      return gulp.src(release.templates.package)
        .pipe(plumber())
        .pipe(flatten())
        .pipe(jeditor(function(package) {
          if(isJavascript) {
            package.dependencies = {
              jquery: 'x.x.x'
            };
            package.main = 'index.js';
          }
          package.name = packageName;
          if(version) {
            package.version = version;
          }
          package.title       = 'Semantic UI - ' + capitalizedComponent;
          package.description = 'Single component release of ' + component;
          package.repository  = {
            type : 'git',
            url  : gitURL
          };
          return package;
        }))
        .pipe(gulp.dest(outputDirectory))
      ;
    });

    // extend composer.json
    gulp.task(task.composer, false, function() {
      return gulp.src(release.templates.composer)
        .pipe(plumber())
        .pipe(flatten())
        .pipe(jeditor(function(composer) {
          if(isJavascript) {
            composer.dependencies = {
              jquery: 'x.x.x'
            };
            composer.main = component + '.js';
          }
          composer.name        = 'semantic/' + component;
          if(version) {
            composer.version     = version;
          }
          composer.description = 'Single component release of ' + component;
          return composer;
        }))
        .pipe(gulp.dest(outputDirectory))
      ;
    });

    // create release notes
    gulp.task(task.notes, false, function() {
      return gulp.src(release.templates.notes)
        .pipe(plumber())
        .pipe(flatten())
        // Remove release notes for lines not mentioning component
        .pipe(replace(regExp.match.unrelatedNotes, regExp.replace.unrelatedNotes))
        .pipe(replace(regExp.match.whitespace, regExp.replace.whitespace))
        .pipe(replace(regExp.match.spacedVersions, regExp.replace.spacedVersions))
        .pipe(replace(regExp.match.spacedLists, regExp.replace.spacedLists))
        .pipe(replace(regExp.match.trim, regExp.replace.trim))
        .pipe(gulp.dest(outputDirectory))
      ;
    });

    // synchronous tasks in orchestrator? I think not
    gulp.task(task.all, false, function(callback) {
      runSequence([
        task.repo,
        task.npm,
        task.bower,
        task.readme,
        task.package,
        task.composer,
        task.notes
      ], callback);
    });

    tasks.push(task.all);

  })(component);
}

runSequence(tasks, callback);

}); gulp.task(‘register repos’, false, function(callback) {

var
  index = -1,
  total = release.components.length,
  process = require('child_process'),
  stream,
  stepRepo
;
console.log('Registering repos with package managers');

// Do Git commands synchronously per component, to avoid issues
stepRepo = function() {
  index = index + 1;
  if(index >= total) {
    return;
  }
  var
    component            = release.components[index],
    outputDirectory      = release.outputRoot + component + '/',
    capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
    packageName          = release.packageRoot + component,
    repoName             = release.repoRoot + capitalizedComponent,
    gitURL               = 'https://github.com/' + release.org + '/' + repoName + '.git',
    exec                 = process.exec,
    execSettings         = {cwd: outputDirectory},
    registerBower        = 'bower register ' + packageName + ' ' + gitURL,
    registerNPM          = 'npm publish'

  ;
  /* One time register
  exec(registerBower, execSettings, function(err, stdout, stderr) {
    stepRepo();
  });
  */
  /* Update npm
  exec(registerNPM, execSettings, function(err, stdout, stderr) {
    console.log(err, stdout, stderr);
    stepRepo();
  });
  */
}
stepRepo();

});

gulp.task(‘update git’, false, function() {

var
  index = -1,
  total = release.components.length,
  stream,
  stepRepo
;
console.log('Handling git');

// Do Git commands synchronously per component, to avoid issues
stepRepo = function() {

  index = index + 1;
  if(index >= total) {
    return;
  }

  var
    component            = release.components[index],
    outputDirectory      = release.outputRoot + component + '/',
    capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
    repoName             = release.repoRoot + capitalizedComponent,
    gitURL               = 'https://github.com/' + release.org + '/' + repoName + '.git',
    repoURL              = 'https://github.com/' + release.org + '/' + repoName + '/',
    gitOptions           = { cwd: outputDirectory },
    quietOptions         = { args: '-q', cwd: outputDirectory },
    isRepository         = fs.existsSync(outputDirectory + '.git/')
    componentPackage     = fs.existsSync(outputDirectory + 'package.json' )
      ? require(outputDirectory + 'package.json')
      : false,
    commitArgs = (oAuth.name !== undefined && oAuth.email !== undefined)
      ? '--author "' + oAuth.name + ' <' + oAuth.email + '>"'
      : '',
    isNewVersion  = (version && componentPackage.version != version),
    mergeMessage  = 'Merged from upstream',
    commitMessage = (isNewVersion)
      ? 'Updated component to version ' + version
      : 'Updated component release from Semantic-UI (Automatic)'
  ;

  console.log('Processing repository:' + outputDirectory);

  if(isRepository) {
    commitFiles();
  }
  else {
    createRepo();
  }

  // standard path
  function commitFiles() {
    // commit files
    console.log('Committing files', commitArgs);
    gulp.src('**/*', gitOptions)
      .pipe(git.add(gitOptions))
      .pipe(git.commit(commitMessage, { args: commitArgs, cwd: outputDirectory }))
      .on('error', function(error) {
        console.log('Nothing new to commit');
        stepRepo();
      })
      .on('finish', function(callback) {
        pullFiles();
      })
    ;
  }
  function pullFiles() {
    console.log('Pulling files');
    git.pull('origin', 'master', { args: '', cwd: outputDirectory }, function(error) {
      if(error && error.message.search("Couldn't find remote ref") != -1) {
        createRepo();
      }
      else {
        console.log('Pull completed successfully');
        mergeCommit();
      }
    });
  };
  function mergeCommit() {
    // commit files
    console.log('Adding merge commit', commitArgs);
    gulp.src('', gitOptions)
      .pipe(git.add(gitOptions))
      .pipe(git.commit(mergeMessage, { args: commitArgs, cwd: outputDirectory }))
      .on('error', function(error) {
        console.log('Nothing new to merge', error);
      })
      .on('finish', function(callback) {
        if(1) {
          tagFiles();
        }
        else {
          pushFiles();
        }
      })
    ;
  }
  function tagFiles() {
    console.log('Tagging new version ', version);
    git.tag(version, 'Updated version from semantic-ui (automatic)', function (err) {
      pushFiles();
    });
  }
  function pushFiles() {
    console.log('Pushing files');
    git.push('origin', 'master', { args: '', cwd: outputDirectory }, function(error) {
      if(error && error.message.search("Couldn't find remote ref") == -1) {
        createRepo();
      }
      console.log('Push completed successfully');
      stepRepo();
    });
  };

  // set-up path
  function createRepo() {
    console.log('Creating repository ' + repoURL);
    github.repos.createFromOrg({
      org      : release.org,
      name     : repoName,
      homepage : release.homepage
    }, function() {
      if(isRepository) {
        addRemote();
      }
      else {
        initRepo();
      }
    });
  }
  function initRepo() {
    console.log('Initializing repository in ' + outputDirectory);
    git.init(gitOptions, function(error) {
      if(error) {
        console.error('Error initializing repo');
        return;
      }
      addRemote();
    });
  }
  function addRemote() {
    console.log('Adding remote origin as ' + gitURL);
    git.addRemote('origin', gitURL, gitOptions, firstPushFiles);
  }
  function firstPushFiles() {
    console.log('Pushing files');
    git.push('origin', 'master', { args: '-u', cwd: outputDirectory }, function(error) {
      if(error) {
        console.log(error);
        pullFiles();
      }
      else {
        console.log('First push completed successfully');
        stepRepo();
      }
    });
  };

};

return stepRepo();

});