Update Jenkins tests

Test jshint and jscs through npm using latest version of jscs and jshint.

Add support for composer.json running phplint and in the future php code
sniffer.

Change-Id: Id8f11f9414fae8313dc18a857a07e11694354dcb
This commit is contained in:
Paladox 2015-11-24 16:03:00 +00:00 committed by Hashar
parent bf5da5eec5
commit 45ebd2d55d
9 changed files with 1034 additions and 932 deletions

4
.gitignore vendored
View file

@ -1,5 +1,7 @@
.svn
*~ *~
*.kate-swp *.kate-swp
.*.swp .*.swp
.directory .directory
/node_modules/
/vendor/
/composer.lock

6
.jscsrc Normal file
View file

@ -0,0 +1,6 @@
{
"preset": "wikimedia",
"requireVarDeclFirst": null,
"requireMultipleVarDecl": null,
"disallowEmptyBlocks": null
}

View file

@ -1,2 +1,4 @@
node_modules
vendor
# upstream libs # upstream libs
resources/lib/ resources/lib/

25
.jshintrc Normal file
View file

@ -0,0 +1,25 @@
{
// Enforcing
"bitwise": true,
"eqeqeq": true,
"freeze": true,
"latedef": true,
"noarg": true,
"nonew": true,
"undef": true,
"unused": true,
"strict": false,
// Relaxing
"es5": false,
// Environment
"browser": true,
"jquery": true,
"globals": {
"mediaWiki": false,
"CodeMirror": false,
"mod": false
}
}

35
Gruntfile.js Normal file
View file

@ -0,0 +1,35 @@
/*jshint node:true */
module.exports = function ( grunt ) {
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
grunt.loadNpmTasks( 'grunt-jsonlint' );
grunt.loadNpmTasks( 'grunt-banana-checker' );
grunt.loadNpmTasks( 'grunt-jscs' );
grunt.initConfig( {
jshint: {
options: {
jshintrc: true
},
all: [
'**/*.js',
'!resources/lib/**',
'!node_modules/**'
]
},
jscs: {
src: '<%= jshint.all %>'
},
banana: {
all: 'i18n/'
},
jsonlint: {
all: [
'**/*.json',
'!node_modules/**'
]
}
} );
grunt.registerTask( 'test', [ 'jshint', 'jscs', 'jsonlint', 'banana' ] );
grunt.registerTask( 'default', 'test' );
};

10
composer.json Normal file
View file

@ -0,0 +1,10 @@
{
"require-dev": {
"jakub-onderka/php-parallel-lint": "0.9"
},
"scripts": {
"test": [
"parallel-lint . --exclude vendor"
]
}
}

13
package.json Normal file
View file

@ -0,0 +1,13 @@
{
"scripts": {
"test": "grunt test"
},
"devDependencies": {
"grunt": "0.4.5",
"grunt-cli": "0.1.13",
"grunt-contrib-jshint": "0.11.3",
"grunt-banana-checker": "0.4.0",
"grunt-jscs": "2.5.0",
"grunt-jsonlint": "1.0.7"
}
}

View file

@ -1,4 +1,3 @@
/* global CodeMirror, mediaWiki */
( function ( mw, $ ) { ( function ( mw, $ ) {
if ( mw.config.get( 'wgCodeEditorCurrentLanguage' ) ) { // If the CodeEditor is used then just exit; if ( mw.config.get( 'wgCodeEditorCurrentLanguage' ) ) { // If the CodeEditor is used then just exit;
return; return;
@ -11,7 +10,7 @@
api = new mw.Api(), api = new mw.Api(),
// function for a textselection function for CodeMirror // function for a textselection function for CodeMirror
cmTextSelection = function ( command, options ) { cmTextSelection = function ( command, options ) {
if ( !codeMirror || codeMirror.getTextArea() !== this[0] ) { if ( !codeMirror || codeMirror.getTextArea() !== this[ 0 ] ) {
return origTextSelection.call( this, command, options ); return origTextSelection.call( this, command, options );
} }
var fn, retval; var fn, retval;
@ -42,13 +41,17 @@
*/ */
encapsulateSelection: function ( options ) { encapsulateSelection: function ( options ) {
return this.each( function () { return this.each( function () {
var insertText, selText, var insertText,
selectPeri = options.selectPeri, selText,
pre = options.pre, post = options.post; selectPeri = options.selectPeri,
pre = options.pre,
post = options.post,
startCursor = codeMirror.doc.getCursor( true ),
endCursor = codeMirror.doc.getCursor( false );
if ( options.selectionStart !== undefined ) { if ( options.selectionStart !== undefined ) {
//fn[command].call( this, options ); // fn[command].call( this, options );
fn.setSelection( { 'start': options.selectionStart, 'end': options.selectionEnd } ); // not tested fn.setSelection( { start: options.selectionStart, end: options.selectionEnd } ); // not tested
} }
selText = codeMirror.doc.getSelection(); selText = codeMirror.doc.getSelection();
@ -80,8 +83,9 @@
var i, var i,
insertText = '', insertText = '',
selTextArr = selText.split( '\n' ); selTextArr = selText.split( '\n' );
for ( i = 0; i < selTextArr.length; i++ ) { for ( i = 0; i < selTextArr.length; i++ ) {
insertText += pre + selTextArr[i] + post; insertText += pre + selTextArr[ i ] + post;
if ( i !== selTextArr.length - 1 ) { if ( i !== selTextArr.length - 1 ) {
insertText += '\n'; insertText += '\n';
} }
@ -96,13 +100,12 @@
insertText = pre + selText + post; insertText = pre + selText + post;
} }
var startCursor = codeMirror.doc.getCursor( true );
if ( options.ownline ) { if ( options.ownline ) {
if ( startCursor.ch !== 0 ) { if ( startCursor.ch !== 0 ) {
insertText = '\n' + insertText; insertText = '\n' + insertText;
pre += '\n'; pre += '\n';
} }
var endCursor = codeMirror.doc.getCursor( false );
if ( codeMirror.doc.getLine( endCursor.line ).length !== endCursor.ch ) { if ( codeMirror.doc.getLine( endCursor.line ).length !== endCursor.ch ) {
insertText += '\n'; insertText += '\n';
post += '\n'; post += '\n';
@ -117,7 +120,7 @@
codeMirror.doc.posFromIndex( codeMirror.doc.indexFromPos( startCursor ) + pre.length + selText.length ) codeMirror.doc.posFromIndex( codeMirror.doc.indexFromPos( startCursor ) + pre.length + selText.length )
); );
} }
}); } );
}, },
/** /**
@ -125,37 +128,35 @@
* in a textarea * in a textarea
*/ */
getCaretPosition: function ( options ) { getCaretPosition: function ( options ) {
var caretPos = codeMirror.doc.indexFromPos( codeMirror.doc.getCursor( true ) ); var caretPos = codeMirror.doc.indexFromPos( codeMirror.doc.getCursor( true ) ),
endPos = codeMirror.doc.indexFromPos( codeMirror.doc.getCursor( false ) );
if ( options.startAndEnd ) { if ( options.startAndEnd ) {
var endPos = codeMirror.doc.indexFromPos( codeMirror.doc.getCursor( false ) );
return [ caretPos, endPos ]; return [ caretPos, endPos ];
} }
return caretPos; return caretPos;
}, },
setSelection: function ( options ) { setSelection: function ( options ) {
return this.each( function () { return this.each( function () {
codeMirror.doc.setSelection( codeMirror.doc.posFromIndex( options.start ), codeMirror.doc.posFromIndex( options.end ) ); codeMirror.doc.setSelection( codeMirror.doc.posFromIndex( options.start ), codeMirror.doc.posFromIndex( options.end ) );
}); } );
}, },
/** /**
* Scroll a textarea to the current cursor position. You can set the cursor * Scroll a textarea to the current cursor position. You can set the cursor
* position with setSelection() * position with setSelection()
* @param options boolean Whether to force a scroll even if the caret position
* is already visible. Defaults to false
*/ */
scrollToCaretPosition: function ( /* options */ ) { scrollToCaretPosition: function () {
return this.each(function () { return this.each( function () {
codeMirror.scrollIntoView( null ); codeMirror.scrollIntoView( null );
}); } );
} }
}; };
switch ( command ) { switch ( command ) {
//case 'getContents': // no params // case 'getContents': // no params
//case 'setContents': // no params with defaults // case 'setContents': // no params with defaults
//case 'getSelection': // no params // case 'getSelection': // no params
case 'encapsulateSelection': case 'encapsulateSelection':
options = $.extend( { options = $.extend( {
pre: '', // Text to insert before the cursor/selection pre: '', // Text to insert before the cursor/selection
@ -203,7 +204,7 @@
break; break;
} }
retval = fn[command].call( this, options ); retval = fn[ command ].call( this, options );
codeMirror.focus(); codeMirror.focus();
return retval; return retval;
@ -218,18 +219,18 @@
$( '#wpTextbox1' ).wikiEditor( $( '#wpTextbox1' ).wikiEditor(
'addToToolbar', 'addToToolbar',
{ {
'section': 'main', section: 'main',
'groups': { groups: {
'codemirror':{ codemirror: {
'tools': { tools: {
'CodeMirror': { CodeMirror: {
label: mw.msg( msg ), label: mw.msg( msg ),
type: 'button', type: 'button',
// FIXME: There should be a better way? // FIXME: There should be a better way?
icon: mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/cm-' + ( codeMirror ? 'on.png' : 'off.png' ), icon: mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/cm-' + ( codeMirror ? 'on.png' : 'off.png' ),
action: { action: {
type: 'callback', type: 'callback',
execute: function( context ) { execute: function ( context ) {
switchCodeMirror( context ); switchCodeMirror( context );
} }
} }
@ -245,7 +246,7 @@
// define JQuery hook for searching and replacing text using JS if CodeMirror is enabled, see Bug: T108711 // define JQuery hook for searching and replacing text using JS if CodeMirror is enabled, see Bug: T108711
$.valHooks.textarea = { $.valHooks.textarea = {
get: function( elem ) { get: function ( elem ) {
if ( elem.id === 'wpTextbox1' && codeMirror ) { if ( elem.id === 'wpTextbox1' && codeMirror ) {
return codeMirror.doc.getValue(); return codeMirror.doc.getValue();
} else if ( originHooksTextarea ) { } else if ( originHooksTextarea ) {
@ -253,7 +254,7 @@
} }
return elem.value; return elem.value;
}, },
set: function( elem, value ) { set: function ( elem, value ) {
if ( elem.id === 'wpTextbox1' && codeMirror ) { if ( elem.id === 'wpTextbox1' && codeMirror ) {
return codeMirror.doc.setValue( value ); return codeMirror.doc.setValue( value );
} else if ( originHooksTextarea ) { } else if ( originHooksTextarea ) {
@ -266,7 +267,7 @@
/** /**
* Save CodeMirror enabled pref. * Save CodeMirror enabled pref.
* *
* @param {Boolean} prefValue True, if CodeMirror should be enabled by default, otherwise false. * @param {boolean} prefValue True, if CodeMirror should be enabled by default, otherwise false.
*/ */
function setCodeEditorPreference( prefValue ) { function setCodeEditorPreference( prefValue ) {
if ( mw.user.isAnon() ) { // Skip it for anon users if ( mw.user.isAnon() ) { // Skip it for anon users
@ -322,10 +323,10 @@
function enableCodeMirror() { function enableCodeMirror() {
var textbox1 = $( '#wpTextbox1' ); var textbox1 = $( '#wpTextbox1' );
if ( textbox1[0].style.display === 'none' ) { if ( textbox1[ 0 ].style.display === 'none' ) {
return; return;
} }
codeMirror = CodeMirror.fromTextArea( textbox1[0], { codeMirror = CodeMirror.fromTextArea( textbox1[ 0 ], {
mwextFunctionSynonyms: mw.config.get( 'extCodeMirrorFunctionSynonyms' ), mwextFunctionSynonyms: mw.config.get( 'extCodeMirrorFunctionSynonyms' ),
mwextTags: mw.config.get( 'extCodeMirrorTags' ), mwextTags: mw.config.get( 'extCodeMirrorTags' ),
mwextDoubleUnderscore: mw.config.get( 'extCodeMirrorDoubleUnderscore' ), mwextDoubleUnderscore: mw.config.get( 'extCodeMirrorDoubleUnderscore' ),
@ -333,7 +334,7 @@
mwextModes: mw.config.get( 'extCodeMirrorExtModes' ), mwextModes: mw.config.get( 'extCodeMirrorExtModes' ),
styleActiveLine: true, styleActiveLine: true,
lineWrapping: true, lineWrapping: true,
readOnly: textbox1[0].readOnly, readOnly: textbox1[ 0 ].readOnly,
// select mediawiki as text input mode // select mediawiki as text input mode
mode: 'text/mediawiki', mode: 'text/mediawiki',
extraKeys: { extraKeys: {
@ -341,7 +342,7 @@
} }
} ); } );
// Our best friend, IE, needs some special css // Our best friend, IE, needs some special css
if ( window.navigator.userAgent.indexOf('Trident/') > -1 ) { if ( window.navigator.userAgent.indexOf( 'Trident/' ) > -1 ) {
$( '.CodeMirror' ).addClass( 'CodeMirrorIE' ); $( '.CodeMirror' ).addClass( 'CodeMirrorIE' );
} }
@ -366,7 +367,7 @@
var $image = $( '<img>' ).attr( { var $image = $( '<img>' ).attr( {
width: 23, width: 23,
height: 22, height: 22,
src: mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/old-cm-' + (codeMirror ? 'on.png' : 'off.png'), src: mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/old-cm-' + ( codeMirror ? 'on.png' : 'off.png' ),
alt: 'CodeMirror', alt: 'CodeMirror',
title: 'CodeMirror', title: 'CodeMirror',
id: 'CodeMirrorButton', id: 'CodeMirrorButton',

File diff suppressed because it is too large Load diff