8
0
Просмотр исходного кода

Merge branch 'master' into i/407-simple

Piotrek Koszuliński 5 лет назад
Родитель
Сommit
188fa1acf5

+ 3 - 1
.travis.yml

@@ -17,7 +17,9 @@ before_install:
 install:
 - yarn install
 script:
-- ./scripts/continuous-integration-run-tests.sh
+- node ./scripts/continuous-integration-script.js
+- yarn run lint
+- yarn run stylelint
 - yarn run docs:api --validate-only
 - 'if [ $TRAVIS_TEST_RESULT -eq 0 ]; then
     travis_wait 30 yarn run docs:build-and-publish-nightly;

+ 3 - 0
package.json

@@ -88,6 +88,7 @@
     "@ckeditor/ckeditor5-track-changes": "^19.0.1",
     "@wiris/mathtype-ckeditor5": "^7.19.0",
     "babel-standalone": "^6.26.0",
+    "coveralls": "^3.1.0",
     "css-loader": "^1.0.0",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^2.0.0",
@@ -159,6 +160,8 @@
   },
   "eslintIgnore": [
     "build/**",
+    "packages/*/build/**",
+    "packages/*/src/lib/**",
     "coverage/**"
   ],
   "workspaces": {

+ 5 - 1
packages/ckeditor5-table/src/tableutils.js

@@ -358,6 +358,8 @@ export default class TableUtils extends Plugin {
 		model.change( writer => {
 			adjustHeadingColumns( table, { first, last }, writer );
 
+			const emptyRowsIndexes = [];
+
 			for ( let removedColumnIndex = last; removedColumnIndex >= first; removedColumnIndex-- ) {
 				for ( const { cell, column, colspan } of [ ...new TableWalker( table ) ] ) {
 					// If colspaned cell overlaps removed column decrease its span.
@@ -372,11 +374,13 @@ export default class TableUtils extends Plugin {
 						// If the cell was the last one in the row, get rid of the entire row.
 						// https://github.com/ckeditor/ckeditor5/issues/6429
 						if ( !cellRow.childCount ) {
-							this.removeRows( table, { at: cellRow.index } );
+							emptyRowsIndexes.push( cellRow.index );
 						}
 					}
 				}
 			}
+
+			emptyRowsIndexes.reverse().forEach( row => this.removeRows( table, { at: row, batch: writer.batch } ) );
 		} );
 	}
 

+ 14 - 0
packages/ckeditor5-table/tests/tableutils.js

@@ -1368,6 +1368,20 @@ describe( 'TableUtils', () => {
 					[ '21', '22' ]
 				] ) );
 			} );
+
+			it( 'should remove the column properly when multiple rows should be removed (because of to row-spans)', () => {
+				setData( model, modelTable( [
+					[ '00', { contents: '01', rowspan: 3 }, { contents: '02', rowspan: 3 } ],
+					[ '10' ],
+					[ '20' ]
+				] ) );
+
+				tableUtils.removeColumns( root.getNodeByPath( [ 0 ] ), { at: 0 } );
+
+				assertEqualMarkup( getData( model, { withoutSelection: true } ), modelTable( [
+					[ '01', '02' ]
+				] ) );
+			} );
 		} );
 
 		describe( 'multiple columns', () => {

+ 0 - 102
scripts/continuous-integration-run-tests.sh

@@ -1,102 +0,0 @@
-#!/bin/bash
-
-# @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
-# For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
-
-packages=$(ls packages -1 | sed -e 's#^ckeditor5\?-\(.\+\)$#\1#')
-
-errorOccured=0
-
-rm -r -f .nyc_output
-mkdir .nyc_output
-
-failedTestsPackages=""
-failedCoveragePackages=""
-
-RED='\033[0;31m'
-NC='\033[0m'
-
-# Travis functions inspired by https://github.com/travis-ci/travis-rubies/blob/a10ba31e3f508650204017332a608ef9bce2c733/build.sh.
-function travis_nanoseconds() {
-  local cmd="date"
-  local format="+%s%N"
-  local os=$(uname)
-
-  if hash gdate > /dev/null 2>&1; then
-    cmd="gdate" # use gdate if available
-  elif [[ "$os" = Darwin ]]; then
-    format="+%s000000000" # fallback to second precision on darwin (does not support %N)
-  fi
-
-  $cmd -u $format
-}
-
-travis_time_start() {
-  travis_timer_id=$(printf %08x $(( RANDOM * RANDOM )))
-  travis_start_time=$(travis_nanoseconds)
-  echo -en "travis_time:start:$travis_timer_id\r${ANSI_CLEAR}"
-}
-
-travis_time_finish() {
-  local result=$?
-  travis_end_time=$(travis_nanoseconds)
-  local duration=$(($travis_end_time-$travis_start_time))
-  echo -en "\ntravis_time:end:$travis_timer_id:start=$travis_start_time,finish=$travis_end_time,duration=$duration\r${ANSI_CLEAR}"
-  return $result
-}
-
-
-fold_start() {
-  echo -e "travis_fold:start:$1\033[33;1m$2\033[0m"
-  travis_time_start
-}
-
-fold_end() {
-  travis_time_finish
-  echo -e "\ntravis_fold:end:$1\n"
-
-}
-
-for package in $packages; do
-
-  fold_start "pkg-$package" "Testing $package${NC}"
-
-  yarn run test -f $package --reporter=dots --production --coverage
-
-  if [ "$?" -ne "0" ]; then
-    echo
-
-    echo -e "💥 ${RED}$package${NC} failed to pass unit tests 💥"
-    failedTestsPackages="$failedTestsPackages $package"
-    errorOccured=1
-  fi
-
-  cp coverage/*/coverage-final.json .nyc_output
-
-  npx nyc check-coverage --branches 100 --functions 100 --lines 100 --statements 100
-
-  if [ "$?" -ne "0" ]; then
-    echo -e "💥 ${RED}$package${NC} doesn't have required code coverage 💥"
-    failedCoveragePackages="$failedCoveragePackages $package"
-    errorOccured=1
-  fi
-
-  fold_end "pkg-$package"
-done;
-
-if [ "$errorOccured" -eq "1" ]; then
-  echo
-  echo "---"
-  echo
-
-  if ! [[ -z $failedTestsPackages ]]; then
-    echo -e "Following packages did not pass unit tests:${RED}$failedTestsPackages${NC}"
-  fi
-
-  if ! [[ -z $failedCoveragePackages ]]; then
-    echo -e "Following packages did not provide required code coverage:${RED}$failedCoveragePackages${NC}"
-  fi
-
-  echo
-  exit 1 # Will break the CI build
-fi

+ 152 - 0
scripts/continuous-integration-script.js

@@ -0,0 +1,152 @@
+#!/usr/bin/env node
+
+/**
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* eslint-env node */
+
+'use strict';
+
+const childProcess = require( 'child_process' );
+const crypto = require( 'crypto' );
+const fs = require( 'fs' );
+const path = require( 'path' );
+const glob = require( 'glob' );
+
+const failedChecks = {
+	dependency: new Set(),
+	unitTests: new Set(),
+	codeCoverage: new Set()
+};
+
+const RED = '\x1B[0;31m';
+const YELLOW = '\x1B[33;1m';
+const NO_COLOR = '\x1B[0m';
+
+const travis = {
+	_lastTimerId: null,
+	_lastStartTime: null,
+
+	foldStart( packageName, foldLabel ) {
+		console.log( `travis_fold:start:${ packageName }${ YELLOW }${ foldLabel }${ NO_COLOR }` );
+		this._timeStart();
+	},
+
+	foldEnd( packageName ) {
+		this._timeFinish();
+		console.log( `\ntravis_fold:end:${ packageName }\n` );
+	},
+
+	_timeStart() {
+		const nanoSeconds = process.hrtime.bigint();
+
+		this._lastTimerId = crypto.createHash( 'md5' ).update( nanoSeconds.toString() ).digest( 'hex' );
+		this._lastStartTime = nanoSeconds;
+
+		// Intentional direct write to stdout, to manually control EOL.
+		process.stdout.write( `travis_time:start:${ this._lastTimerId }\r\n` );
+	},
+
+	_timeFinish() {
+		const travisEndTime = process.hrtime.bigint();
+		const duration = travisEndTime - this._lastStartTime;
+
+		// Intentional direct write to stdout, to manually control EOL.
+		process.stdout.write( `\ntravis_time:end:${ this._lastTimerId }:start=${ this._lastStartTime },` +
+			`finish=${ travisEndTime },duration=${ duration }\r\n` );
+	}
+};
+
+childProcess.execSync( 'rm -r -f .nyc_output' );
+childProcess.execSync( 'mkdir .nyc_output' );
+childProcess.execSync( 'rm -r -f .out' );
+childProcess.execSync( 'mkdir .out' );
+
+const packages = childProcess.execSync( 'ls packages -1', {
+	encoding: 'utf8'
+} ).toString().trim().split( '\n' );
+
+for ( const fullPackageName of packages ) {
+	const simplePackageName = fullPackageName.replace( /^ckeditor5?-/, '' );
+	const foldLabelName = 'pkg-' + simplePackageName;
+
+	travis.foldStart( foldLabelName, `Testing ${ fullPackageName }${ NO_COLOR }` );
+
+	appendCoverageReport();
+
+	runSubprocess( 'npx', [ 'ckeditor5-dev-tests-check-dependencies', `packages/${ fullPackageName }` ], simplePackageName, 'dependency',
+		'have a dependency problem' );
+
+	const testArguments = [ 'run', 'test', '-f', simplePackageName, '--reporter=dots', '--production', '--coverage' ];
+	runSubprocess( 'yarn', testArguments, simplePackageName, 'unitTests', 'failed to pass unit tests' );
+
+	childProcess.execSync( 'cp coverage/*/coverage-final.json .nyc_output' );
+
+	const nyc = [ 'nyc', 'check-coverage', '--branches', '100', '--functions', '100', '--lines', '100', '--statements', '100' ];
+	runSubprocess( 'npx', nyc, simplePackageName, 'codeCoverage', 'doesn\'t have required code coverage' );
+
+	travis.foldEnd( foldLabelName );
+}
+
+console.log( 'Uploading combined code coverage report…' );
+childProcess.execSync( 'npx coveralls < .out/combined_lcov.info' );
+console.log( 'Done' );
+
+if ( Object.values( failedChecks ).some( checksSet => checksSet.size > 0 ) ) {
+	console.log( '\n---\n' );
+
+	showFailedCheck( 'dependency', 'The following packages have dependencies that are not included in its package.json' );
+	showFailedCheck( 'unitTests', 'The following packages did not pass unit tests' );
+	showFailedCheck( 'codeCoverage', 'The following packages did not provide required code coverage' );
+
+	process.exit( 1 ); // Exit code 1 will break the CI build.
+}
+
+/*
+ * @param {String} binaryName - Name of a CLI binary to be called.
+ * @param {String[]} cliArguments - An array of arguments to be passed to the `binaryName`.
+ * @param {String} packageName - Checked package name.
+ * @param {String} checkName - A key associated with the problem in the `failedChecks` dictionary.
+ * @param {String} failMessage - Message to be shown if check failed.
+ */
+function runSubprocess( binaryName, cliArguments, packageName, checkName, failMessage ) {
+	const subprocess = childProcess.spawnSync( binaryName, cliArguments, {
+		encoding: 'utf8',
+		shell: true
+	} );
+
+	console.log( subprocess.stdout );
+
+	if ( subprocess.stderr ) {
+		console.log( subprocess.stderr );
+	}
+
+	if ( subprocess.status !== 0 ) {
+		failedChecks.unitTests.add( packageName );
+		console.log( `💥 ${ RED }${ packageName }${ NO_COLOR } ` + failMessage + ' 💥' );
+	}
+}
+
+function showFailedCheck( checkKey, errorMessage ) {
+	const failedPackages = failedChecks[ checkKey ];
+
+	if ( failedPackages.size ) {
+		console.log( `${ errorMessage }: ${ RED }${ Array.from( failedPackages.values() ).join( ', ' ) }${ NO_COLOR }` );
+	}
+}
+
+function appendCoverageReport() {
+	// Appends coverage data to the combined code coverage info file. It's used because all the results
+	// needs to be uploaded at once (#6742).
+	const matches = glob.sync( 'coverage/*/lcov.info' );
+
+	matches.forEach( filePath => {
+		const buffer = fs.readFileSync( filePath );
+
+		fs.writeFileSync( [ '.out', 'combined_lcov.info' ].join( path.sep ), buffer, {
+			flag: 'as'
+		} );
+	} );
+}