Browse Source

Changes to install and update dev tasks.

Szymon Kupś 9 years ago
parent
commit
8286f64b30

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

@@ -40,7 +40,7 @@ module.exports = ( config ) => {
 			}
 		} );
 
-		updateTask( ckeditor5Path, packageJSON, config.WORKSPACE_DIR, options[ 'npm-update' ] );
+		updateTask( installTask, ckeditor5Path, packageJSON, config.WORKSPACE_DIR, options[ 'npm-update' ] );
 	} );
 
 	gulp.task( 'status', () => {

+ 2 - 8
dev/tasks/dev/tasks/install.js

@@ -20,9 +20,8 @@ const log = require( '../utils/log' );
  * 2. If NPM module name is provided - gets GitHub URL from NPM and clones the repository.
  * 3. If path on disk is provided - it is used directly.
  * 4. Runs `npm install` in package repository.
- * 5. If package exists in `ckeditor5/node_modules/` - runs `npm uninstall package_name`.
- * 6. Links package directory into `ckeditor5/node_modules/`.
- * 7. Adds dependency to `ckeditor5/package.json`.
+ * 5. Links package directory into `ckeditor5/node_modules/`.
+ * 6. Adds dependency to `ckeditor5/package.json`.
  *
  * @param {String} ckeditor5Path Absolute path to `ckeditor5` repository.
  * @param {String} workspaceRoot Relative path to workspace root directory.
@@ -89,11 +88,6 @@ module.exports = ( ckeditor5Path, workspaceRoot, name ) => {
 
 		const linkPath = path.join( ckeditor5Path, 'node_modules', urlInfo.name );
 
-		if ( tools.isDirectory( linkPath ) ) {
-			log.out( `Uninstalling ${ urlInfo.name } from CKEditor5 node_modules...` );
-			tools.npmUninstall( ckeditor5Path, urlInfo.name );
-		}
-
 		log.out( `Linking ${ linkPath } to ${ repositoryPath }...` );
 		tools.linkDirectories( repositoryPath, linkPath );
 

+ 47 - 35
dev/tasks/dev/tasks/update.js

@@ -9,20 +9,26 @@ const tools = require( '../utils/tools' );
 const git = require( '../utils/git' );
 const path = require( 'path' );
 const log = require( '../utils/log' );
-const installTask = require( './install' );
 
 /**
- * 1. Get CKEditor5 dependencies from package.json file.
- * 2. Scan workspace for repositories that match dependencies from package.json file.
- * 3. Run GIT pull command on each repository found.
+ * 1. Get CKEditor 5 dependencies from package.json in main CKEditor 5 repository.
+ * 2. If dependency's repository is already cloned in workspace:
+ * 		2.1. Fetch and checkout to specified branch.
+ * 		2.2. Pull changes to that branch.
+ * 		2.3. if --npm-update was specified run npm update --dev in that repository.
+ *		2.4. Recreate symbolic link between repo and main node_modules.
+ * 3. If dependency's repository is not cloned yet - run gulp install on this dependency.
+ * 4. Remove symbolic links to dependencies that are not used in current package.json configuration.
+ * 5. if --npm-update was specified run npm update --dev in main CKeditor 5 repository.
  *
+ * @param {Function} installTask Install task to use on each dependency that is missing from workspace.
  * @param {String} ckeditor5Path Path to main CKEditor5 repository.
  * @param {Object} packageJSON Parsed package.json file from CKEditor5 repository.
  * @param {String} workspaceRoot Relative path to workspace root.
  * @param {Boolean} runNpmUpdate When set to true `npm update` will be executed inside each plugin repository
  * and inside CKEditor 5 repository.
  */
-module.exports = ( ckeditor5Path, packageJSON, workspaceRoot, runNpmUpdate ) => {
+module.exports = ( installTask, ckeditor5Path, packageJSON, workspaceRoot, runNpmUpdate ) => {
 	const workspaceAbsolutePath = path.join( ckeditor5Path, workspaceRoot );
 
 	// Get all CKEditor dependencies from package.json.
@@ -31,45 +37,51 @@ module.exports = ( ckeditor5Path, packageJSON, workspaceRoot, runNpmUpdate ) =>
 	if ( dependencies ) {
 		const directories = tools.getCKE5Directories( workspaceAbsolutePath );
 
-		if ( directories.length ) {
-			for ( let dependency in dependencies ) {
-				const repositoryURL = dependencies[ dependency ];
-				const urlInfo = git.parseRepositoryUrl( repositoryURL );
-				const repositoryAbsolutePath = path.join( workspaceAbsolutePath, dependency );
+		for ( let dependency in dependencies ) {
+			const repositoryURL = dependencies[ dependency ];
+			const urlInfo = git.parseRepositoryUrl( repositoryURL );
+			const repositoryAbsolutePath = path.join( workspaceAbsolutePath, dependency );
 
-				// Check if repository's directory already exists.
-				if ( directories.indexOf( urlInfo.name ) > -1 ) {
-					log.out( `Checking out ${ urlInfo.name } to ${ urlInfo.branch }...` );
-					git.checkout( repositoryAbsolutePath, urlInfo.branch );
+			// Check if repository's directory already exists.
+			if ( directories.indexOf( urlInfo.name ) > -1 ) {
+				log.out( `Checking out ${ urlInfo.name } to ${ urlInfo.branch }...` );
+				git.checkout( repositoryAbsolutePath, urlInfo.branch );
 
-					log.out( `Pulling changes to ${ urlInfo.name }...` );
-					git.pull( repositoryAbsolutePath, urlInfo.branch );
+				log.out( `Pulling changes to ${ urlInfo.name }...` );
+				git.pull( repositoryAbsolutePath, urlInfo.branch );
 
-					if ( runNpmUpdate ) {
-						log.out( `Running "npm update" in ${ urlInfo.name }...` );
-						tools.npmUpdate( repositoryAbsolutePath );
-					}
+				if ( runNpmUpdate ) {
+					log.out( `Running "npm update" in ${ urlInfo.name }...` );
+					tools.npmUpdate( repositoryAbsolutePath );
+				}
 
-					try {
-						log.out( `Linking ${ repositoryURL }...` );
-						tools.linkDirectories( repositoryAbsolutePath, path.join( ckeditor5Path, 'node_modules', dependency ) );
-					} catch ( error ) {
-						log.err( error );
-					}
-				} else {
-					// Directory does not exits in workspace - install it.
-					installTask( ckeditor5Path, workspaceRoot, repositoryURL );
+				try {
+					log.out( `Linking ${ repositoryURL }...` );
+					tools.linkDirectories( repositoryAbsolutePath, path.join( ckeditor5Path, 'node_modules', dependency ) );
+				} catch ( error ) {
+					log.err( error );
 				}
+			} else {
+				// Directory does not exits in workspace - install it.
+				installTask( ckeditor5Path, workspaceRoot, repositoryURL );
 			}
+		}
 
-			if ( runNpmUpdate ) {
-				log.out( `Running "npm update" in CKEditor5 repository...` );
-				tools.npmUpdate( ckeditor5Path );
-			}
-		} else {
-			log.out( 'No CKEditor5 plugins in development mode.' );
+		if ( runNpmUpdate ) {
+			log.out( `Running "npm update" in CKEditor5 repository...` );
+			tools.npmUpdate( ckeditor5Path );
 		}
 	} else {
 		log.out( 'No CKEditor5 dependencies found in package.json file.' );
 	}
+
+	// Remove symlinks not used in this configuration.
+	const nodeModulesPath = path.join( ckeditor5Path, 'node_modules' );
+	const symlinks = tools.getCKE5Symlinks( nodeModulesPath );
+	symlinks
+		.filter( dir => typeof dependencies[ dir ] == 'undefined' )
+		.forEach( dir => {
+			log.out( `Removing symbolic link to ${ dir }.` );
+			tools.removeSymlink( path.join( nodeModulesPath, dir ) );
+		} );
 };

+ 4 - 8
dev/tests/dev/install.js

@@ -33,7 +33,6 @@ describe( 'dev-install', () => {
 		spies.checkout = sinon.stub( git, 'checkout' );
 		spies.getGitUrlFromNpm = sinon.stub( tools, 'getGitUrlFromNpm' );
 		spies.readPackageName = sinon.stub( tools, 'readPackageName' );
-		spies.npmUninstall = sinon.stub( tools, 'npmUninstall' );
 	} );
 
 	afterEach( () => {
@@ -47,7 +46,7 @@ describe( 'dev-install', () => {
 
 		installTask( ckeditor5Path, workspacePath, repositoryUrl );
 
-		sinon.assert.calledThrice( spies.isDirectory );
+		sinon.assert.calledTwice( spies.isDirectory );
 		sinon.assert.calledOnce( spies.parseUrl );
 		sinon.assert.calledWithExactly( spies.parseUrl, repositoryUrl );
 
@@ -65,9 +64,6 @@ describe( 'dev-install', () => {
 
 		const linkPath = path.join( ckeditor5Path, 'node_modules', urlInfo.name );
 
-		sinon.assert.calledOnce( spies.npmUninstall );
-		sinon.assert.calledWithExactly( spies.npmUninstall, ckeditor5Path, urlInfo.name );
-
 		sinon.assert.calledOnce( spies.linkDirectories );
 		sinon.assert.calledWithExactly( spies.linkDirectories, repositoryPath, linkPath );
 
@@ -88,7 +84,7 @@ describe( 'dev-install', () => {
 
 		installTask( ckeditor5Path, workspacePath, moduleName );
 
-		sinon.assert.calledThrice( spies.isDirectory );
+		sinon.assert.calledTwice( spies.isDirectory );
 		sinon.assert.calledTwice( spies.parseUrl );
 		sinon.assert.calledWithExactly( spies.parseUrl.firstCall, moduleName );
 		expect( spies.parseUrl.firstCall.returnValue ).to.equal( null );
@@ -128,7 +124,7 @@ describe( 'dev-install', () => {
 
 		installTask( ckeditor5Path, workspacePath, '../ckeditor5-core' );
 
-		sinon.assert.calledThrice( spies.isDirectory );
+		sinon.assert.calledTwice( spies.isDirectory );
 		sinon.assert.calledOnce( spies.readPackageName );
 	} );
 
@@ -139,7 +135,7 @@ describe( 'dev-install', () => {
 
 		installTask( ckeditor5Path, workspacePath, '/ckeditor5-core' );
 
-		sinon.assert.calledThrice( spies.isDirectory );
+		sinon.assert.calledTwice( spies.isDirectory );
 		sinon.assert.calledOnce( spies.readPackageName );
 	} );
 

+ 131 - 15
dev/tests/dev/update.js

@@ -24,6 +24,8 @@ describe( 'dev-update', () => {
 		spies.checkout = sinon.stub( git, 'checkout' );
 		spies.pull = sinon.stub( git, 'pull' );
 		spies.npmUpdate = sinon.stub( tools, 'npmUpdate' );
+		spies.linkDirectories = sinon.stub( tools, 'linkDirectories' );
+		spies.removeSymlink = sinon.stub( tools, 'removeSymlink' );
 	} );
 
 	afterEach( () => {
@@ -32,7 +34,9 @@ describe( 'dev-update', () => {
 
 	it( 'should update dev repositories', () => {
 		const dirs = [ 'ckeditor5-core', 'ckeditor5-devtest' ];
+		const installTask = sinon.spy();
 		spies.getDirectories = sinon.stub( tools, 'getCKE5Directories' ).returns( dirs );
+		spies.getCKE5Symlinks = sinon.stub( tools, 'getCKE5Symlinks' ).returns( [] );
 
 		const json = {
 			dependencies: {
@@ -42,61 +46,173 @@ describe( 'dev-update', () => {
 			}
 		};
 
-		updateTask( ckeditor5Path, json, workspaceRoot, true );
+		updateTask( installTask, ckeditor5Path, json, workspaceRoot, true );
 
+		const repoPath1 = path.join( workspaceAbsolutePath, dirs[ 0 ] );
+		const repoPath2 = path.join( workspaceAbsolutePath, dirs[ 1 ] );
+
+		sinon.assert.calledTwice( spies.checkout );
+		sinon.assert.calledWithExactly( spies.checkout.firstCall, repoPath1, 'master' );
+		sinon.assert.calledWithExactly( spies.checkout.secondCall, repoPath2, 'new-branch' );
 		sinon.assert.calledTwice( spies.pull );
-		sinon.assert.calledWithExactly( spies.pull.firstCall, path.join( workspaceAbsolutePath, dirs[ 0 ] ), 'master' );
-		sinon.assert.calledWithExactly( spies.pull.secondCall, path.join( workspaceAbsolutePath, dirs[ 1 ] ), 'new-branch' );
+		sinon.assert.calledWithExactly( spies.pull.firstCall, repoPath1, 'master' );
+		sinon.assert.calledWithExactly( spies.pull.secondCall, repoPath2, 'new-branch' );
 
 		sinon.assert.calledThrice( spies.npmUpdate );
 		sinon.assert.calledWithExactly( spies.npmUpdate.firstCall, path.join( workspaceAbsolutePath, dirs[ 0 ] ) );
 		sinon.assert.calledWithExactly( spies.npmUpdate.secondCall, path.join( workspaceAbsolutePath, dirs[ 1 ] ) );
 		sinon.assert.calledWithExactly( spies.npmUpdate.thirdCall, ckeditor5Path );
+
+		sinon.assert.calledOnce( spies.getCKE5Symlinks );
+		sinon.assert.notCalled( spies.removeSymlink );
+		sinon.assert.notCalled( installTask );
 	} );
 
-	it( 'should update dev repositories without running npm update', () => {
-		const dirs = [ 'ckeditor5-core' ];
+	it( 'should install missing dependencies', () => {
+		const dirs = [ 'ckeditor5-core', 'ckeditor5-devtest' ];
+		const installTask = sinon.spy();
 		spies.getDirectories = sinon.stub( tools, 'getCKE5Directories' ).returns( dirs );
+		spies.getCKE5Symlinks = sinon.stub( tools, 'getCKE5Symlinks' ).returns( [] );
 
 		const json = {
 			dependencies: {
 				'ckeditor5-core': 'ckeditor/ckeditor5-core',
 				'ckeditor5-devtest': 'ckeditor/ckeditor5-devtest#new-branch',
+				'ckeditor5-ui': 'ckeditor/ckeditor5-ui',
 				'other-plugin': '1.2.3'
 			}
 		};
 
-		updateTask( ckeditor5Path, json, workspaceRoot, false );
-		sinon.assert.calledWithExactly( spies.pull.firstCall, path.join( workspaceAbsolutePath, dirs[ 0 ] ), 'master' );
-		sinon.assert.notCalled( spies.npmUpdate );
+		updateTask( installTask, ckeditor5Path, json, workspaceRoot, true );
+
+		const repoPath1 = path.join( workspaceAbsolutePath, dirs[ 0 ] );
+		const repoPath2 = path.join( workspaceAbsolutePath, dirs[ 1 ] );
+
+		sinon.assert.calledTwice( spies.checkout );
+		sinon.assert.calledWithExactly( spies.checkout.firstCall, repoPath1, 'master' );
+		sinon.assert.calledWithExactly( spies.checkout.secondCall, repoPath2, 'new-branch' );
+		sinon.assert.calledTwice( spies.pull );
+		sinon.assert.calledWithExactly( spies.pull.firstCall, repoPath1, 'master' );
+		sinon.assert.calledWithExactly( spies.pull.secondCall, repoPath2, 'new-branch' );
+
+		sinon.assert.calledThrice( spies.npmUpdate );
+		sinon.assert.calledWithExactly( spies.npmUpdate.firstCall, path.join( workspaceAbsolutePath, dirs[ 0 ] ) );
+		sinon.assert.calledWithExactly( spies.npmUpdate.secondCall, path.join( workspaceAbsolutePath, dirs[ 1 ] ) );
+		sinon.assert.calledWithExactly( spies.npmUpdate.thirdCall, ckeditor5Path );
+
+		sinon.assert.calledOnce( installTask );
+		sinon.assert.calledWithExactly( installTask, ckeditor5Path, workspaceRoot, 'ckeditor/ckeditor5-ui' );
+
+		sinon.assert.calledOnce( spies.getCKE5Symlinks );
+		sinon.assert.notCalled( spies.removeSymlink );
 	} );
 
-	it( 'should not update when no dependencies are found', () => {
-		spies.getDirectories = sinon.stub( tools, 'getCKE5Directories' );
+	it( 'should remove symlinks that are not needed', () => {
+		const dirs = [ 'ckeditor5-core', 'ckeditor5-devtest' ];
+		const installTask = sinon.spy();
+		spies.getDirectories = sinon.stub( tools, 'getCKE5Directories' ).returns( dirs );
+		spies.getCKE5Symlinks = sinon.stub( tools, 'getCKE5Symlinks' ).returns( [ 'ckeditor5-unused' ] );
+
 		const json = {
 			dependencies: {
+				'ckeditor5-core': 'ckeditor/ckeditor5-core',
+				'ckeditor5-devtest': 'ckeditor/ckeditor5-devtest#new-branch',
 				'other-plugin': '1.2.3'
 			}
 		};
 
-		updateTask( ckeditor5Path, json, workspaceRoot, false );
+		updateTask( installTask, ckeditor5Path, json, workspaceRoot, true );
+
+		const repoPath1 = path.join( workspaceAbsolutePath, dirs[ 0 ] );
+		const repoPath2 = path.join( workspaceAbsolutePath, dirs[ 1 ] );
+
+		sinon.assert.calledTwice( spies.checkout );
+		sinon.assert.calledWithExactly( spies.checkout.firstCall, repoPath1, 'master' );
+		sinon.assert.calledWithExactly( spies.checkout.secondCall, repoPath2, 'new-branch' );
+		sinon.assert.calledTwice( spies.pull );
+		sinon.assert.calledWithExactly( spies.pull.firstCall, repoPath1, 'master' );
+		sinon.assert.calledWithExactly( spies.pull.secondCall, repoPath2, 'new-branch' );
+
+		sinon.assert.calledThrice( spies.npmUpdate );
+		sinon.assert.calledWithExactly( spies.npmUpdate.firstCall, path.join( workspaceAbsolutePath, dirs[ 0 ] ) );
+		sinon.assert.calledWithExactly( spies.npmUpdate.secondCall, path.join( workspaceAbsolutePath, dirs[ 1 ] ) );
+		sinon.assert.calledWithExactly( spies.npmUpdate.thirdCall, ckeditor5Path );
+
+		sinon.assert.calledOnce( spies.getCKE5Symlinks );
+		sinon.assert.notCalled( installTask );
+
+		sinon.assert.calledOnce( spies.removeSymlink );
+		sinon.assert.calledWithExactly( spies.removeSymlink, path.join( ckeditor5Path, 'node_modules', 'ckeditor5-unused' ) );
+	} );
+
+	it( 'should catch linking errors', () => {
+		const log = require( '../../tasks/dev/utils/log' );
+		const dirs = [ 'ckeditor5-core', 'ckeditor5-devtest' ];
+		const installTask = sinon.spy();
+		const outSpy = sinon.spy();
+		const errSpy = sinon.spy();
+		spies.getDirectories = sinon.stub( tools, 'getCKE5Directories' ).returns( dirs );
+		spies.getCKE5Symlinks = sinon.stub( tools, 'getCKE5Symlinks' ).returns( [ 'ckeditor5-unused' ] );
+		spies.linkDirectories.throws();
+
+		log.configure( outSpy, errSpy );
+
+		const json = {
+			dependencies: {
+				'ckeditor5-core': 'ckeditor/ckeditor5-core',
+				'ckeditor5-devtest': 'ckeditor/ckeditor5-devtest#new-branch',
+				'other-plugin': '1.2.3'
+			}
+		};
+
+		updateTask( installTask, ckeditor5Path, json, workspaceRoot, false );
+
+		const repoPath1 = path.join( workspaceAbsolutePath, dirs[ 0 ] );
+		const repoPath2 = path.join( workspaceAbsolutePath, dirs[ 1 ] );
+
+		sinon.assert.calledTwice( spies.checkout );
+		sinon.assert.calledWithExactly( spies.checkout.firstCall, repoPath1, 'master' );
+		sinon.assert.calledWithExactly( spies.checkout.secondCall, repoPath2, 'new-branch' );
+		sinon.assert.calledTwice( spies.pull );
+		sinon.assert.calledWithExactly( spies.pull.firstCall, repoPath1, 'master' );
+		sinon.assert.calledWithExactly( spies.pull.secondCall, repoPath2, 'new-branch' );
 
-		sinon.assert.notCalled( spies.pull );
 		sinon.assert.notCalled( spies.npmUpdate );
+
+		sinon.assert.calledOnce( spies.getCKE5Symlinks );
+		sinon.assert.notCalled( installTask );
+
+		sinon.assert.calledOnce( spies.removeSymlink );
+		sinon.assert.calledWithExactly( spies.removeSymlink, path.join( ckeditor5Path, 'node_modules', 'ckeditor5-unused' ) );
+		sinon.assert.calledTwice( errSpy );
 	} );
 
-	it( 'should not update when no plugins in dev mode', () => {
-		spies.getDirectories = sinon.stub( tools, 'getCKE5Directories' ).returns( [] );
+	it( 'should skip updating if no dependencies found', () => {
+		spies.getDependencies.restore();
+		spies.getDependencies = sinon.stub( tools, 'getCKEditorDependencies' ).returns( null );
+		const dirs = [ 'ckeditor5-core', 'ckeditor5-devtest' ];
+		const installTask = sinon.spy();
+		spies.getDirectories = sinon.stub( tools, 'getCKE5Directories' ).returns( dirs );
+		spies.getCKE5Symlinks = sinon.stub( tools, 'getCKE5Symlinks' ).returns( [] );
+
 		const json = {
 			dependencies: {
+				'ckeditor5-core': 'ckeditor/ckeditor5-core',
 				'ckeditor5-devtest': 'ckeditor/ckeditor5-devtest#new-branch',
 				'other-plugin': '1.2.3'
 			}
 		};
 
-		updateTask( ckeditor5Path, json, workspaceRoot, false );
+		updateTask( installTask, ckeditor5Path, json, workspaceRoot, false );
 
+		sinon.assert.notCalled( spies.checkout );
 		sinon.assert.notCalled( spies.pull );
+
 		sinon.assert.notCalled( spies.npmUpdate );
+
+		sinon.assert.calledOnce( spies.getCKE5Symlinks );
+		sinon.assert.notCalled( installTask );
+
+		sinon.assert.notCalled( spies.removeSymlink );
 	} );
 } );