8
0
Эх сурвалжийг харах

Merge branch 'master' into t/187

Oskar Wrobel 9 жил өмнө
parent
commit
a2de0ed57b

+ 32 - 30
dev/tasks/build/tasks.js

@@ -318,38 +318,40 @@ module.exports = ( config ) => {
 					.pipe( filter( '*.js' ) )
 					.pipe( mirror( formatStreams ) );
 			}
+		},
+
+		register() {
+			gulp.task( 'build', callback => {
+				runSequence( 'build:clean:all', 'build:themes', 'build:js', callback );
+			} );
+
+			gulp.task( 'build:clean:all', tasks.clean.all );
+			gulp.task( 'build:clean:themes', tasks.clean.themes );
+			gulp.task( 'build:clean:js', () => tasks.clean.js( args ) );
+
+			gulp.task( 'build:themes', ( callback ) => {
+				runSequence( 'build:clean:themes', 'build:icons', 'build:sass', callback );
+			} );
+
+			gulp.task( 'build:sass', () => tasks.build.sass( args ) );
+			gulp.task( 'build:icons', () => tasks.build.icons( args ) );
+			gulp.task( 'build:js', [ 'build:clean:js' ], () => tasks.build.js( args ) );
+
+			// Tasks specific for preparing build with unmodified source files. Uses by `gulp docs` or `gulp bundle`.
+			gulp.task( 'build:clean:js:esnext', () => tasks.clean.js( { formats: [ 'esnext' ] } ) );
+			gulp.task( 'build:clean:themes:esnext', () => tasks.clean.themes( { formats: [ 'esnext' ] } ) );
+			gulp.task( 'build:sass:esnext', () => tasks.build.sass( { formats: [ 'esnext' ] } ) );
+			gulp.task( 'build:icons:esnext', () => tasks.build.icons( { formats: [ 'esnext' ] } ) );
+			gulp.task( 'build:js:esnext', [ 'build:clean:js:esnext' ], () => tasks.build.js( { formats: [ 'esnext' ] } ) );
+			gulp.task( 'build:themes:esnext', ( callback ) => {
+				runSequence( 'build:clean:themes:esnext', 'build:icons:esnext', 'build:sass:esnext', callback );
+			} );
+
+			// Tasks specific for testing under node.
+			gulp.task( 'build:clean:js:cjs', () => tasks.clean.js( { formats: [ 'cjs' ] } ) );
+			gulp.task( 'build:js:cjs', [ 'build:clean:js:cjs' ], () => tasks.build.js( { formats: [ 'cjs' ] } ) );
 		}
 	};
 
-	gulp.task( 'build', callback => {
-		runSequence( 'build:clean:all', 'build:themes', 'build:js', callback );
-	} );
-
-	gulp.task( 'build:clean:all', tasks.clean.all );
-	gulp.task( 'build:clean:themes', tasks.clean.themes );
-	gulp.task( 'build:clean:js', () => tasks.clean.js( args ) );
-
-	gulp.task( 'build:themes', ( callback ) => {
-		runSequence( 'build:clean:themes', 'build:icons', 'build:sass', callback );
-	} );
-
-	gulp.task( 'build:sass', () => tasks.build.sass( args ) );
-	gulp.task( 'build:icons', () => tasks.build.icons( args ) );
-	gulp.task( 'build:js', [ 'build:clean:js' ], () => tasks.build.js( args ) );
-
-	// Tasks specific for preparing build with unmodified source files. Uses by `gulp docs` or `gulp bundle`.
-	gulp.task( 'build:clean:js:esnext', () => tasks.clean.js( { formats: [ 'esnext' ] } ) );
-	gulp.task( 'build:clean:themes:esnext', () => tasks.clean.themes( { formats: [ 'esnext' ] } ) );
-	gulp.task( 'build:sass:esnext', () => tasks.build.sass( { formats: [ 'esnext' ] } ) );
-	gulp.task( 'build:icons:esnext', () => tasks.build.icons( { formats: [ 'esnext' ] } ) );
-	gulp.task( 'build:js:esnext', [ 'build:clean:js:esnext' ], () => tasks.build.js( { formats: [ 'esnext' ] } ) );
-	gulp.task( 'build:themes:esnext', ( callback ) => {
-		runSequence( 'build:clean:themes:esnext', 'build:icons:esnext', 'build:sass:esnext', callback );
-	} );
-
-	// Tasks specific for testing under node.
-	gulp.task( 'build:clean:js:cjs', () => tasks.clean.js( { formats: [ 'cjs' ] } ) );
-	gulp.task( 'build:js:cjs', [ 'build:clean:js:cjs' ], () => tasks.build.js( { formats: [ 'cjs' ] } ) );
-
 	return tasks;
 };

+ 1 - 1
dev/tasks/bundle/buildclassiceditor.js

@@ -24,7 +24,7 @@
  */
 import '../../../node_modules/regenerator-runtime/runtime.js';
 
-import ClassicEditor from '../../../build/esnext/ckeditor5/creator-classic/classic.js';
+import ClassicEditor from '../../../build/esnext/ckeditor5/editor-classic/classic.js';
 import Delete from '../../../build/esnext/ckeditor5/delete/delete.js';
 import Enter from '../../../build/esnext/ckeditor5/enter/enter.js';
 import Typing from '../../../build/esnext/ckeditor5/typing/typing.js';

+ 19 - 17
dev/tasks/bundle/tasks.js

@@ -93,27 +93,29 @@ module.exports = ( config ) => {
 
 				return utils.saveFileFromStreamAsMinified( stream, bundleDir );
 			}
-		}
-	};
+		},
 
-	gulp.task( 'bundle:clean', tasks.clean );
-	gulp.task( 'bundle:generate', [ 'bundle:clean', 'build:js:esnext', 'build:themes:esnext' ], tasks.generate );
-	gulp.task( 'bundle:minify:js', tasks.minify.js );
-	gulp.task( 'bundle:minify:css', tasks.minify.css );
-	gulp.task( 'bundle:next', tasks.next );
+		register() {
+			gulp.task( 'bundle:clean', tasks.clean );
+			gulp.task( 'bundle:generate', [ 'bundle:clean', 'build:js:esnext', 'build:themes:esnext' ], tasks.generate );
+			gulp.task( 'bundle:minify:js', tasks.minify.js );
+			gulp.task( 'bundle:minify:css', tasks.minify.css );
+			gulp.task( 'bundle:next', tasks.next );
 
-	gulp.task( 'bundle', ( callback ) => {
-		runSequence( 'bundle:generate', [ 'bundle:minify:js', 'bundle:minify:css' ], () => {
-			const files = [ 'ckeditor.js', 'ckeditor.css', 'ckeditor.min.js', 'ckeditor.min.css' ];
-			const filesStats = utils.getFilesSizeStats( files, bundleDir );
+			gulp.task( 'bundle', ( callback ) => {
+				runSequence( 'bundle:generate', [ 'bundle:minify:js', 'bundle:minify:css' ], () => {
+					const files = [ 'ckeditor.js', 'ckeditor.css', 'ckeditor.min.js', 'ckeditor.min.css' ];
+					const filesStats = utils.getFilesSizeStats( files, bundleDir );
 
-			// Show bundle summary on console.
-			utils.showFilesSummary( 'Bundle summary', filesStats );
+					// Show bundle summary on console.
+					utils.showFilesSummary( 'Bundle summary', filesStats );
 
-			// Finish the task.
-			callback();
-		} );
-	} );
+					// Finish the task.
+					callback();
+				} );
+			} );
+		}
+	};
 
 	return tasks;
 };

+ 1 - 1
dev/tasks/bundle/utils.js

@@ -68,8 +68,8 @@ const utils = {
 	/**
 	 * Get normal and gzipped size of every passed file in specified directory.
 	 *
-	 * @param {String} [rootDir='']
 	 * @param {Array<String>} files
+	 * @param {String} [rootDir='']
 	 * @returns {Array<Object>} List with file size data
 	 */
 	getFilesSizeStats( files, rootDir = '' ) {

+ 49 - 34
dev/tasks/dev/tasks.js

@@ -26,47 +26,62 @@ module.exports = ( config ) => {
 		( msg ) => gutil.log( gutil.colors.red( msg ) )
 	);
 
-	gulp.task( 'init', () => {
-		initTask( installTask, ckeditor5Path, packageJSON, config.WORKSPACE_DIR );
-	} );
+	const tasks = {
+		updateRepositories() {
+			const options = minimist( process.argv.slice( 2 ), {
+				boolean: [ 'npm-update' ],
+				default: {
+					'npm-update': false
+				}
+			} );
 
-	gulp.task( 'create-package', ( done ) => {
-		pluginCreateTask( ckeditor5Path, config.WORKSPACE_DIR )
-			.then( done )
-			.catch( ( error )  => done( error ) );
-	} );
+			return updateTask( installTask, ckeditor5Path, packageJSON, config.WORKSPACE_DIR, options[ 'npm-update' ] );
+		},
 
-	gulp.task( 'update', () => {
-		const options = minimist( process.argv.slice( 2 ), {
-			boolean: [ 'npm-update' ],
-			default: {
-				'npm-update': false
-			}
-		} );
+		checkStatus() {
+			return statusTask( ckeditor5Path, packageJSON, config.WORKSPACE_DIR );
+		},
+
+		initRepository() {
+			return initTask( installTask, ckeditor5Path, packageJSON, config.WORKSPACE_DIR );
+		},
 
-		updateTask( installTask, ckeditor5Path, packageJSON, config.WORKSPACE_DIR, options[ 'npm-update' ] );
-	} );
+		createPackage( done ) {
+			pluginCreateTask( ckeditor5Path, config.WORKSPACE_DIR )
+				.then( done )
+				.catch( ( error ) => done( error ) );
+		},
 
-	gulp.task( 'status', () => {
-		statusTask( ckeditor5Path, packageJSON, config.WORKSPACE_DIR );
-	} );
+		relink() {
+			return relinkTask( ckeditor5Path, packageJSON, config.WORKSPACE_DIR );
+		},
 
-	gulp.task( 'relink', () => {
-		relinkTask( ckeditor5Path, packageJSON, config.WORKSPACE_DIR );
-	} );
+		installPackage() {
+			const options = minimist( process.argv.slice( 2 ), {
+				string: [ 'package' ],
+				default: {
+					plugin: ''
+				}
+			} );
 
-	gulp.task( 'install', () => {
-		const options = minimist( process.argv.slice( 2 ), {
-			string: [ 'package' ],
-			default: {
-				plugin: ''
+			if ( options.package ) {
+				return installTask( ckeditor5Path, config.WORKSPACE_DIR, options.package );
+			} else {
+				throw new Error( 'Please provide a package to install: gulp dev-install --plugin <path|GitHub URL|name>' );
 			}
-		} );
+		},
 
-		if ( options.package ) {
-			installTask( ckeditor5Path, config.WORKSPACE_DIR, options.package );
-		} else {
-			throw new Error( 'Please provide a package to install: gulp dev-install --plugin <path|GitHub URL|name>' );
+		register() {
+			gulp.task( 'init', tasks.initRepository );
+			gulp.task( 'create-package', tasks.createPackage );
+			gulp.task( 'update', tasks.updateRepositories );
+			gulp.task( 'pull', tasks.updateRepositories );
+			gulp.task( 'status', tasks.checkStatus );
+			gulp.task( 'st', tasks.checkStatus );
+			gulp.task( 'relink', tasks.relink );
+			gulp.task( 'install', tasks.installPackage );
 		}
-	} );
+	};
+
+	return tasks;
 };

+ 16 - 12
dev/tasks/dev/tasks/create-package.js

@@ -14,14 +14,15 @@ const log = require( '../utils/log' );
 /**
  * 1. Ask for new package name.
  * 2. Ask for initial version.
- * 3. Ask for GitHub URL.
+ * 3. Ask for GitHub path.
  * 4. Initialize repository.
- * 5. Copy files to new repository.
- * 6. Update package.json file in new package's repository.
- * 7. Update package.json file in CKEditor5 repository.
- * 8. Create initial commit.
- * 9. Link new package.
- * 10. Call `npm install` in package repository.
+ * 5. Add remote.
+ * 6. Copy files to new repository.
+ * 7. Update package.json file in new package's repository.
+ * 8. Update package.json file in CKEditor5 repository.
+ * 9. Create initial commit.
+ * 10. Link new package.
+ * 11. Call `npm install` in package repository.
  *
  * @param {String} ckeditor5Path Path to main CKEditor5 repository.
  * @param {String} workspaceRoot Relative path to workspace root.
@@ -58,7 +59,7 @@ module.exports = ( ckeditor5Path, workspaceRoot ) => {
 	let packageFullName;
 	let repositoryPath;
 	let packageVersion;
-	let gitHubUrl;
+	let gitHubPath;
 	let packageDescription;
 
 	return inquiries.getPackageName()
@@ -76,10 +77,10 @@ module.exports = ( ckeditor5Path, workspaceRoot ) => {
 		.then( result => {
 			packageVersion = result;
 
-			return inquiries.getPackageGitHubUrl( packageName );
+			return inquiries.getPackageGitHubPath( packageName );
 		} )
 		.then( result => {
-			gitHubUrl = result;
+			gitHubPath = result;
 
 			return inquiries.getPackageDescription();
 		} )
@@ -89,12 +90,15 @@ module.exports = ( ckeditor5Path, workspaceRoot ) => {
 			log.out( `Initializing repository ${ repositoryPath }...` );
 			git.initializeRepository( repositoryPath );
 
+			log.out( `Adding remote ${ repositoryPath }...` );
+			git.addRemote( repositoryPath, gitHubPath );
+
 			log.out( `Copying files into ${ repositoryPath }...` );
 
 			for ( let destination in fileStructure ) {
 				tools.copyTemplateFiles( fileStructure[ destination ], path.join( repositoryPath, destination ), {
 					'{{AppName}}': packageFullName,
-					'{{GitHubRepositoryPath}}': gitHubUrl,
+					'{{GitHubRepositoryPath}}': gitHubPath,
 					'{{ProjectDescription}}': packageDescription
 				} );
 			}
@@ -112,7 +116,7 @@ module.exports = ( ckeditor5Path, workspaceRoot ) => {
 				if ( !json.dependencies ) {
 					json.dependencies = {};
 				}
-				json.dependencies[ packageName ] = gitHubUrl;
+				json.dependencies[ packageName ] = gitHubPath;
 				json.dependencies = tools.sortObject( json.dependencies );
 
 				return json;

+ 17 - 1
dev/tasks/dev/utils/git.js

@@ -6,6 +6,7 @@
 'use strict';
 
 const tools = require( './tools' );
+const defaultOrigin = 'origin';
 
 module.exports = {
 
@@ -89,7 +90,7 @@ module.exports = {
 	pull( repositoryLocation, branchName ) {
 		const pullCommands = [
 			`cd ${ repositoryLocation }`,
-			`git pull origin ${ branchName }`
+			`git pull ${ defaultOrigin } ${ branchName }`
 		];
 
 		tools.shExec( pullCommands.join( ' && ' ) );
@@ -142,5 +143,20 @@ module.exports = {
 		];
 
 		tools.shExec( commitCommands.join( ' && ' ) );
+	},
+
+	/**
+	 * Adds remote to repository under specified path.
+	 *
+	 * @param {String} repositoryPath
+	 * @param {String} gitHubPath
+	 */
+	addRemote( repositoryPath, gitHubPath ) {
+		const addRemoteCommands = [
+			`cd ${ repositoryPath }`,
+			`git remote add ${ defaultOrigin } git@github.com:${ gitHubPath }.git`
+		];
+
+		tools.shExec( addRemoteCommands.join( ' && ' ) );
 	}
 };

+ 10 - 9
dev/tasks/dev/utils/inquiries.js

@@ -6,9 +6,10 @@
 'use strict';
 
 const inquirer = require( 'inquirer' );
+const sanitize = require( './sanitize' );
 const DEFAULT_PLUGIN_NAME_PREFIX = 'ckeditor5-';
 const DEFAULT_PLUGIN_VERSION = '0.0.1';
-const DEFAULT_GITHUB_URL_PREFIX = 'ckeditor/';
+const DEFAULT_GITHUB_PATH_PREFIX = 'ckeditor/';
 
 module.exports = {
 	getPackageName() {
@@ -50,16 +51,16 @@ module.exports = {
 		} );
 	},
 
-	getPackageGitHubUrl( packageName ) {
-		const defaultGitHubUrl = DEFAULT_GITHUB_URL_PREFIX + packageName;
+	getPackageGitHubPath( packageName ) {
+		const defaultGitHubPath = DEFAULT_GITHUB_PATH_PREFIX + packageName;
 
 		return new Promise( ( resolve ) => {
 			inquirer.prompt( [ {
-				name: 'gitHubUrl',
-				message: 'Enter package\'s GitHub URL:',
-				default: defaultGitHubUrl
+				name: 'gitHubPath',
+				message: 'Enter package\'s GitHub path:',
+				default: defaultGitHubPath
 			} ], ( answers ) => {
-				resolve( answers.gitHubUrl );
+				resolve( answers.gitHubPath );
 			} );
 		} );
 	},
@@ -68,9 +69,9 @@ module.exports = {
 		return new Promise( ( resolve ) => {
 			inquirer.prompt( [ {
 				name: 'description',
-				message: 'Package description (one sentence):'
+				message: 'Package description (one sentence, must end with period):'
 			} ], ( answers ) => {
-				resolve( answers.description || '' );
+				resolve( sanitize.appendPeriodIfMissing( answers.description || '' ) );
 			} );
 		} );
 	}

+ 18 - 0
dev/tasks/dev/utils/sanitize.js

@@ -0,0 +1,18 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+module.exports = {
+	appendPeriodIfMissing( text ) {
+		text = text.trim();
+
+		if ( text.length > 0 && !text.endsWith( '.' ) ) {
+			text += '.';
+		}
+
+		return text;
+	}
+};

+ 32 - 24
dev/tasks/docs/tasks.js

@@ -10,30 +10,38 @@ const jsdoc = require( 'gulp-jsdoc3' );
 const path = require( 'path' );
 
 module.exports = ( config ) => {
-	gulp.task( 'docs', [ 'build:js:esnext' ], function( cb ) {
-		const esnextBuildPath = path.join( config.ROOT_DIR, config.BUILD_DIR, 'esnext' );
-		const jsDocConfig = {
-			opts: {
-				encoding: 'utf8',
-				destination: path.join( config.BUILD_DIR, 'docs' ),
-				recurse: true,
-				access: 'all'
-			},
-			plugins: [
-				'node_modules/jsdoc/plugins/markdown',
-				'dev/tasks/docs/plugins/comment-fixer'
-			]
-		};
+	const tasks = {
+		buildDocs( cb ) {
+			const esnextBuildPath = path.join( config.ROOT_DIR, config.BUILD_DIR, 'esnext' );
+			const jsDocConfig = {
+				opts: {
+					encoding: 'utf8',
+					destination: path.join( config.BUILD_DIR, 'docs' ),
+					recurse: true,
+					access: 'all'
+				},
+				plugins: [
+					'node_modules/jsdoc/plugins/markdown',
+					'dev/tasks/docs/plugins/comment-fixer'
+				]
+			};
 
-		const patterns = [
-			'README.md',
-			// Add all js and jsdoc files, including tests (which can contain utils).
-			path.join( esnextBuildPath, '**', '*.@(js|jsdoc)' ),
-			// Filter out libs.
-			'!' + path.join( esnextBuildPath, 'ckeditor5', '*', 'lib', '**', '*' )
-		];
+			const patterns = [
+				'README.md',
+				// Add all js and jsdoc files, including tests (which can contain utils).
+				path.join( esnextBuildPath, '**', '*.@(js|jsdoc)' ),
+				// Filter out libs.
+				'!' + path.join( esnextBuildPath, 'ckeditor5', '*', 'lib', '**', '*' )
+			];
 
-		gulp.src( patterns, { read: false } )
-			.pipe( jsdoc( jsDocConfig, cb ) );
-	} );
+			gulp.src( patterns, { read: false } )
+				.pipe( jsdoc( jsDocConfig, cb ) );
+		},
+
+		register() {
+			gulp.task( 'docs', [ 'build:js:esnext' ], tasks.buildDocs );
+		}
+	};
+
+	return tasks;
 };

+ 7 - 4
dev/tasks/lint/tasks.js

@@ -6,7 +6,6 @@ const gulp = require( 'gulp' );
 const jshint = require( 'gulp-jshint' );
 const jscs = require( 'gulp-jscs' );
 const fs = require( 'fs' );
-const guppy = require( 'git-guppy' )( gulp );
 const gulpFilter = require( 'gulp-filter' );
 const gutil = require( 'gulp-util' );
 
@@ -30,6 +29,8 @@ module.exports = ( config ) => {
 		 * @returns {Stream}
 		 */
 		lintStaged() {
+			const guppy = require( 'git-guppy' )( gulp );
+
 			return guppy.stream( 'pre-commit', { base: './' } )
 				.pipe( gulpFilter( src ) )
 				.pipe( lint() )
@@ -48,12 +49,14 @@ module.exports = ( config ) => {
 				gutil.log( gutil.colors.red( 'Linting failed, commit aborted' ) );
 				process.exit( 1 );
 			}
+		},
+
+		register() {
+			gulp.task( 'lint', tasks.lint );
+			gulp.task( 'lint-staged', tasks.lintStaged );
 		}
 	};
 
-	gulp.task( 'lint', tasks.lint );
-	gulp.task( 'lint-staged', tasks.lintStaged );
-
 	return tasks;
 
 	/**

+ 48 - 10
dev/tasks/test/tasks.js

@@ -16,19 +16,27 @@ const buildUtils = require( '../build/utils' );
 const benderConfig = require( '../../../bender' );
 
 /**
- * Defines Node.js testing task.
+ * Defines Node.js testing task and development tools testing tasks.
  *
- * To run tests under node:
+ * To run tests under Node.js:
  *
  *		gulp test:node
  *
- * To run build before testing:
+ * To run build under Node.js before testing:
  *
  *		gulp test:node:build
  *
- * To run testing with code coverage:
+ * To run testing under Node.js with code coverage:
  *
  *		gulp test:node:coverage
+ *
+ * To run development tools tests:
+ *
+ * 		gulp test:dev
+ *
+ * To run development tools tests with coverage:
+ *
+ * 		gulp test:dev:coverage
  */
 module.exports = () => {
 	const ignoreRegexp = /\/\* ?bender-tags:.*\bbrowser-only\b.*\*\//;
@@ -52,7 +60,7 @@ module.exports = () => {
 		 *
 		 * @returns {Stream}
 		 */
-		prepareCoverage() {
+		prepareNodeCoverage() {
 			const src = benderConfig.coverage.paths.map( ( item ) => {
 				return item.replace( 'build/amd/', 'build/cjs/' );
 			} );
@@ -115,13 +123,43 @@ module.exports = () => {
 		 */
 		skipIgnored() {
 			return filterBy( file => !file.contents.toString().match( ignoreRegexp ) );
+		},
+
+		/**
+		 * Runs dev unit tests.
+		 *
+		 * @returns {Stream}
+		 */
+		devTest() {
+			return gulp.src( 'dev/tests/**/*.js' )
+				.pipe( mocha() )
+				.pipe( tasks.coverage ? istanbul.writeReports() : buildUtils.noop() );
+		},
+
+		/**
+		 * Prepares files for coverage report.
+		 *
+		 * @returns {Stream}
+		 */
+		prepareDevCoverage() {
+			tasks.coverage = true;
+
+			return gulp.src( 'dev/tasks/**/*.js' )
+				.pipe( istanbul() )
+				.pipe( istanbul.hookRequire() );
+		},
+
+		register() {
+			gulp.task( 'test:node:pre-coverage', [ 'build:js:cjs' ], tasks.prepareNodeCoverage );
+			gulp.task( 'test:node', tasks.testInNode );
+			gulp.task( 'test:node:build', [ 'build:js:cjs' ] , tasks.testInNode );
+			gulp.task( 'test:node:coverage', [ 'build:js:cjs', 'test:node:pre-coverage' ], tasks.testInNode );
+
+			gulp.task( 'test:dev:pre-coverage', tasks.prepareDevCoverage );
+			gulp.task( 'test:dev', tasks.devTest );
+			gulp.task( 'test:dev:coverage', [ 'test:dev:pre-coverage' ], tasks.devTest );
 		}
 	};
 
-	gulp.task( 'test:node:pre-coverage', [ 'build:js:cjs' ], tasks.prepareCoverage );
-	gulp.task( 'test:node', tasks.testInNode );
-	gulp.task( 'test:node:build', [ 'build:js:cjs' ] , tasks.testInNode );
-	gulp.task( 'test:node:coverage', [ 'build:js:cjs', 'test:node:pre-coverage' ], tasks.testInNode );
-
 	return tasks;
 };

+ 0 - 14
dev/tests/build/utils.js

@@ -193,20 +193,6 @@ describe( 'build-utils', () => {
 		} );
 	} );
 
-	describe( 'getBabelPlugins', () => {
-		it( 'should return plugins for amd format', () => {
-			expect( utils.getBabelPlugins( 'amd' ) ).to.be.an( 'array' );
-		} );
-
-		it( 'should throw an exception when incorrect format is provided', () => {
-			const format = 'incorrect-format';
-
-			expect( () => {
-				utils.getBabelPlugins( format );
-			} ).to.throw( Error, `Incorrect format: ${ format }` );
-		} );
-	} );
-
 	describe( 'getConversionStreamGenerator', () => {
 		beforeEach( () => {
 			sandbox.stub( utils, 'getBabelOptionsForSource', () => 'src' );

+ 9 - 5
dev/tests/dev/create-package.js

@@ -24,7 +24,7 @@ describe( 'dev-create-package', () => {
 	const packageName = 'package-name';
 	const applicationName = 'Full application name';
 	const packageVersion = '0.0.1';
-	const gitHubUrl = 'ckeditor5/package-name';
+	const gitHubPath = 'ckeditor5/package-name';
 	const packageDescription = 'Package description.';
 
 	beforeEach( () => createSpies() );
@@ -37,12 +37,13 @@ describe( 'dev-create-package', () => {
 			getPackageName: sinon.stub( inquiries, 'getPackageName' ).returns( new Promise( ( r ) => r( packageName ) ) ),
 			getApplicationName: sinon.stub( inquiries, 'getApplicationName' ).returns( new Promise( ( r ) => r( applicationName ) ) ),
 			getPackageVersion: sinon.stub( inquiries, 'getPackageVersion' ).returns( new Promise( ( r ) => r( packageVersion ) ) ),
-			getPackageGitHubUrl: sinon.stub( inquiries, 'getPackageGitHubUrl' ).returns( new Promise( ( r ) => r( gitHubUrl ) ) ),
+			getPackageGitHubPath: sinon.stub( inquiries, 'getPackageGitHubPath' ).returns( new Promise( ( r ) => r( gitHubPath ) ) ),
 			getPackageDescription: sinon.stub( inquiries, 'getPackageDescription' ).returns( new Promise( ( r ) => r( packageDescription ) ) ),
 			initializeRepository: sinon.stub( git, 'initializeRepository' ),
 			updateJSONFile: sinon.stub( tools, 'updateJSONFile' ),
 			copy: sinon.stub( tools, 'copyTemplateFiles' ),
-			initialCommit: sinon.stub( git, 'initialCommit' )
+			initialCommit: sinon.stub( git, 'initialCommit' ),
+			addRemote: sinon.stub( git, 'addRemote' )
 		};
 	}
 
@@ -62,10 +63,13 @@ describe( 'dev-create-package', () => {
 			expect( spies.getPackageName.calledOnce ).to.equal( true );
 			expect( spies.getApplicationName.calledOnce ).to.equal( true );
 			expect( spies.getPackageVersion.calledOnce ).to.equal( true );
-			expect( spies.getPackageGitHubUrl.calledOnce ).to.equal( true );
+			expect( spies.getPackageGitHubPath.calledOnce ).to.equal( true );
 			expect( spies.getPackageDescription.calledOnce ).to.equal( true );
 			expect( spies.initializeRepository.calledOnce ).to.equal( true );
 			expect( spies.initializeRepository.firstCall.args[ 0 ] ).to.equal( repositoryPath );
+			expect( spies.addRemote.calledOnce ).to.equal( true );
+			expect( spies.addRemote.firstCall.args[ 0 ] ).to.equal( repositoryPath );
+			expect( spies.addRemote.firstCall.args[ 1 ] ).to.equal( gitHubPath );
 			expect( spies.copy.called ).to.equal( true );
 			expect( spies.updateJSONFile.calledTwice ).to.equal( true );
 			expect( spies.updateJSONFile.firstCall.args[ 0 ] ).to.equal( path.join( repositoryPath, 'package.json' ) );
@@ -77,7 +81,7 @@ describe( 'dev-create-package', () => {
 			updateFn = spies.updateJSONFile.secondCall.args[ 1 ];
 			json = updateFn( {} );
 			expect( json.dependencies ).to.be.an( 'object' );
-			expect( json.dependencies[ packageName ] ).to.equal( gitHubUrl );
+			expect( json.dependencies[ packageName ] ).to.equal( gitHubPath );
 			expect( spies.initialCommit.calledOnce ).to.equal( true );
 			expect( spies.initialCommit.firstCall.args[ 0 ] ).to.equal( packageName );
 			expect( spies.initialCommit.firstCall.args[ 1 ] ).to.equal( repositoryPath );

+ 19 - 0
dev/tests/dev/git.js

@@ -243,5 +243,24 @@ describe( 'utils', () => {
 				expect( shExecStub.firstCall.args[ 0 ] ).to.equal( commitCommands.join( ' && ' ) );
 			} );
 		} );
+
+		describe( 'addRemote', () => {
+			it( 'should be defined', () => expect( git.addRemote ).to.be.a( 'function' ) );
+
+			it( 'should execute add remote commands', () => {
+				const shExecStub = sandbox.stub( tools, 'shExec' );
+				const gitHubPath = 'ckeditor5/ckeditor5-plugin-name';
+				const repositoryPath = '/path/to/repo';
+				const addRemoteCommands = [
+					`cd ${ repositoryPath }`,
+					`git remote add origin git@github.com:${ gitHubPath }.git`
+				];
+
+				git.addRemote( repositoryPath, gitHubPath );
+
+				expect( shExecStub.calledOnce ).to.equal( true );
+				expect( shExecStub.firstCall.args[ 0 ] ).to.equal( addRemoteCommands.join( ' && ' ) );
+			} );
+		} );
 	} );
 } );

+ 44 - 0
dev/tests/dev/sanitize.js

@@ -0,0 +1,44 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global describe, it */
+
+'use strict';
+
+const sanitize = require( '../../tasks/dev/utils/sanitize' );
+const chai = require( 'chai' );
+const expect = chai.expect;
+
+describe( 'utils', () => {
+	describe( 'sanitize', () => {
+		describe( 'appendPeriodIfMissing', () => {
+			it( 'should be defined', () => expect( sanitize.appendPeriodIfMissing ).to.be.a( 'function' ) );
+
+			it( 'should trim whitespace/new lines to empty string', () => {
+				const sanitized = sanitize.appendPeriodIfMissing( '\n\t\r ' );
+
+				expect( sanitized ).to.equal( '' );
+			} );
+
+			it( 'should add period at the end if missing ', () => {
+				const sanitized = sanitize.appendPeriodIfMissing( 'sometext' );
+
+				expect( sanitized ).to.equal( 'sometext.' );
+			} );
+
+			it( 'should not add period at the end if present', () => {
+				const sanitized = sanitize.appendPeriodIfMissing( 'sometext.' );
+
+				expect( sanitized ).to.equal( 'sometext.' );
+			} );
+
+			it( 'should leave empty string as is', () => {
+				const sanitized = sanitize.appendPeriodIfMissing( '' );
+
+				expect( sanitized ).to.equal( '' );
+			} );
+		} );
+	} );
+} );

+ 19 - 0
dev/tests/dev/status.js

@@ -11,6 +11,9 @@ const sinon = require( 'sinon' );
 const tools = require( '../../tasks/dev/utils/tools' );
 const git = require( '../../tasks/dev/utils/git' );
 const path = require( 'path' );
+const chai = require( 'chai' );
+const expect = chai.expect;
+const gulp = require( 'gulp' );
 
 describe( 'dev-status', () => {
 	const statusTask = require( '../../tasks/dev/tasks/status' );
@@ -109,3 +112,19 @@ describe( 'dev-status', () => {
 		sinon.assert.calledWithExactly( writeErrorSpy, error );
 	} );
 } );
+
+describe( 'gulp task status', () => {
+	const tasks = gulp.tasks;
+
+	it( 'should be available', () => {
+		expect( tasks ).to.have.property( 'status' );
+		expect( tasks.status.fn ).to.be.a( 'function' );
+	} );
+
+	it( 'should have an alias', () => {
+		expect( tasks ).to.have.property( 'st' );
+		expect( tasks.st.fn ).to.be.a( 'function' );
+
+		expect( tasks.st.fn ).to.equal( tasks.status.fn );
+	} );
+} );

+ 19 - 0
dev/tests/dev/update.js

@@ -11,6 +11,9 @@ const sinon = require( 'sinon' );
 const tools = require( '../../tasks/dev/utils/tools' );
 const git = require( '../../tasks/dev/utils/git' );
 const path = require( 'path' );
+const chai = require( 'chai' );
+const expect = chai.expect;
+const gulp = require( 'gulp' );
 
 describe( 'dev-update', () => {
 	const updateTask = require( '../../tasks/dev/tasks/update' );
@@ -236,3 +239,19 @@ describe( 'dev-update', () => {
 		sinon.assert.notCalled( spies.removeSymlink );
 	} );
 } );
+
+describe( 'gulp task update', () => {
+	const tasks = gulp.tasks;
+
+	it( 'should be available', () => {
+		expect( tasks ).to.have.property( 'update' );
+		expect( tasks.update.fn ).to.be.a( 'function' );
+	} );
+
+	it( 'should have an alias', () => {
+		expect( tasks ).to.have.property( 'pull' );
+		expect( tasks.pull.fn ).to.be.a( 'function' );
+
+		expect( tasks.pull.fn ).to.equal( tasks.update.fn );
+	} );
+} );

+ 6 - 6
gulpfile.js

@@ -16,12 +16,12 @@ const config = {
 	]
 };
 
-require( './dev/tasks/build/tasks' )( config );
-require( './dev/tasks/bundle/tasks' )( config );
-require( './dev/tasks/dev/tasks' )( config );
-require( './dev/tasks/lint/tasks' )( config );
-require( './dev/tasks/test/tasks' )( config );
-require( './dev/tasks/docs/tasks' )( config );
+require( './dev/tasks/build/tasks' )( config ).register();
+require( './dev/tasks/bundle/tasks' )( config ).register();
+require( './dev/tasks/dev/tasks' )( config ).register();
+require( './dev/tasks/lint/tasks' )( config ).register();
+require( './dev/tasks/test/tasks' )( config ).register();
+require( './dev/tasks/docs/tasks' )( config ).register();
 
 gulp.task( 'default', [ 'build' ] );
 gulp.task( 'pre-commit', [ 'lint-staged' ] );

+ 10 - 15
package.json

@@ -9,11 +9,11 @@
   ],
   "dependencies": {
     "ckeditor5-basic-styles": "ckeditor/ckeditor5-basic-styles",
-    "ckeditor5-creator-classic": "ckeditor/ckeditor5-creator-classic",
     "ckeditor5-delete": "ckeditor/ckeditor5-delete",
+    "ckeditor5-editor-classic": "ckeditor/ckeditor5-editor-classic",
     "ckeditor5-engine": "ckeditor/ckeditor5-engine",
     "ckeditor5-enter": "ckeditor/ckeditor5-enter",
-    "ckeditor5-formats": "ckeditor/ckeditor5-formats",
+    "ckeditor5-headings": "ckeditor/ckeditor5-headings",
     "ckeditor5-paragraph": "ckeditor/ckeditor5-paragraph",
     "ckeditor5-theme-lark": "ckeditor/ckeditor5-theme-lark",
     "ckeditor5-typing": "ckeditor/ckeditor5-typing",
@@ -25,13 +25,13 @@
   },
   "devDependencies": {
     "almond": "^0.3.0",
-    "babel-core": "^6.4.0",
-    "babel-plugin-transform-es2015-modules-amd": "^6.1.18",
-    "babel-plugin-transform-es2015-modules-commonjs": "^6.2.0",
+    "babel-core": "^6.9.0",
+    "babel-plugin-transform-es2015-modules-amd": "^6.8.0",
+    "babel-plugin-transform-es2015-modules-commonjs": "^6.10.0",
     "babel-preset-es2015-rollup": "^1.1.1",
     "benderjs": "^0.4.1",
     "benderjs-chai": "^0.2.0",
-    "benderjs-coverage": "^0.2.1",
+    "benderjs-coverage": "benderjs/benderjs-coverage#t/4",
     "benderjs-mocha": "^0.3.0",
     "benderjs-promise": "^0.1.0",
     "benderjs-sinon": "^0.3.0",
@@ -56,19 +56,17 @@
     "gulp-replace": "^0.5.4",
     "gulp-sourcemaps": "^1.6.0",
     "gulp-svg-sprite": "^1.2.19",
-    "gulp-uglify": "^1.5.3",
+    "gulp-uglify": "^1.5.4",
     "gulp-util": "^3.0.7",
-    "gulp-watch": "4.3.5",
+    "gulp-watch": "^4.3.7",
     "guppy-pre-commit": "^0.3.0",
     "gzip-size": "^3.0.0",
     "inquirer": "^0.11.0",
-    "istanbul": "^0.4.1",
     "jsdoc": "^3.4.0",
     "jshint": "^2.9.1",
     "jshint-reporter-jscs": "^0.1.0",
     "merge-stream": "^1.0.0",
     "minimist": "^1.2.0",
-    "mocha": "^2.2.5",
     "mockery": "^1.4.0",
     "multipipe": "^0.3.0",
     "ncp": "^2.0.0",
@@ -82,7 +80,8 @@
     "semver": "^5.1.0",
     "shelljs": "^0",
     "sinon": "^1.17.0",
-    "through2": "^2.0.0"
+    "through2": "^2.0.0",
+    "uglify": "^0.1.5"
   },
   "engines": {
     "node": ">=5.0.0",
@@ -95,9 +94,5 @@
   "repository": {
     "type": "git",
     "url": "https://github.com/ckeditor/ckeditor5.git"
-  },
-  "scripts": {
-    "test": "mocha dev/tests --recursive",
-    "coverage": "istanbul cover _mocha dev/tests/ -- --recursive"
   }
 }

+ 2 - 2
src/editor/editor.js

@@ -100,7 +100,7 @@ export default class Editor {
 	}
 
 	/**
-	 * Loads and initilizes plugins specified in `config.features`.
+	 * Loads and initilizes plugins specified in config features.
 	 *
 	 * @returns {Promise} A promise which resolves once the initialization is completed.
 	 */
@@ -112,7 +112,7 @@ export default class Editor {
 			.then( initPlugins );
 
 		function loadPlugins() {
-			let plugins = config.features || [];
+			let plugins = config.get( 'features' ) || [];
 
 			// Handle features passed as a string.
 			if ( !isArray( plugins ) ) {

+ 1 - 1
tests/_utils-tests/modeltesteditor.js

@@ -56,7 +56,7 @@ describe( 'ModelTestEditor', () => {
 		} );
 
 		it( 'should set data of the first root', () => {
-			editor.document.createRoot( 'secondRoot' );
+			editor.document.createRoot( '$root', 'secondRoot' );
 
 			editor.setData( 'foo' );
 

+ 2 - 2
tests/editor/standardeditor.js

@@ -74,7 +74,7 @@ describe( 'StandardEditor', () => {
 
 		it( 'should set data of the first root', () => {
 			editor.document.createRoot();
-			editor.document.createRoot( 'secondRoot' );
+			editor.document.createRoot( '$root', 'secondRoot' );
 
 			editor.editing.createRoot( 'div' );
 			editor.editing.createRoot( 'div', 'secondRoot' );
@@ -101,7 +101,7 @@ describe( 'StandardEditor', () => {
 
 		it( 'should set data of the first root', () => {
 			editor.document.createRoot();
-			editor.document.createRoot( 'secondRoot' );
+			editor.document.createRoot( '$root', 'secondRoot' );
 
 			setData( editor.document, 'foo' );