Intégration continue/Points d'entrée
Nous avons standardisé les tests de notre code sur les outils suivants :
Langage | Lanceur de commande | Etape Lint | Style du code | Analyse statique | Tests unitaires | Documentation |
---|---|---|---|---|---|---|
PHP | composer | php-parallel-lint
|
PHP CodeSniffer avec mediawiki-tools-codesniffer | Phan avec mediawiki-phan-config | PHPUnit | Doxygen |
JavaScript | npm & grunt | grunt-eslint avec eslint-config-wikimedia | grunt-eslint avec eslint-config-wikimedia | QUnit | JSDoc | |
JSON | N/A | json-schema | N/A | N/A | ||
i18n | grunt-banana-checker | N/A | N/A | N/A | documentation sur la traduction des messages | |
CSS/LESS | grunt-stylelint avec stylelint-config-wikimedia | N/A | N/A | N/A | ||
Java | maven wrapper (maven) | ? | ? | ? | ? | ? |
Python | tox | flake8 | unittest
pytest[1] |
sphinx? | ||
Ruby | bundler | rubocop | ? | rake test | ? |
La documentation sur la manière de configurer et d'initialiser ces outils est décrite ci-dessous.
JavaScript
Tester JavaScript
Nous utilisons npm test
comme point d'accès.
Si votre projet possède des fichiers JavaScript, il doit avoir au moins un fichier package.json
qui définit un script test
et le fichier package-lock.json
associé pour assurer la cohérence des opérations de CI et les mises à jour de sécurité.
Pour les extensions MediaWiki et les habillages, le script npm test
ne doit pas exécuter les tests du projet, mais seulement les linters.
Tout ce qui est différent des linter (comme, les tests unitaires ou d'intégration) est exécuté à partir des canaux classiques MediaWiki; si vous souhaitez avoir un lanceur particulier, vous devez le mettre dans un autre script.
Vous aurez besoin du fichier de configuration .eslintrc.json
dans votre projet (voir Lint et JavaScript).
Regardez dans l'un des projets listés dans la section d'exemple ci-dessous pour avoir un exemple de ces fichiers.
npm
échouent avec un message node: No such file or directory relatif à un fichier ou un répertoire non trouvé, il est possible que vous deviez installer le paquet nodejs-legacy
.
Lanceur de tâches Grunt
Si votre projet possède des processus de construction complexes, ou que c'est une extension ou un habillage qui bénéficiera de la vérification i18n et du linting des fichiers JSON, la convention est d'utiliser Grunt comme lanceur de tâches.
Votre projet contient encore un fichier package.json
, qui possède une dépendance sur grunt
et définit "test": "grunt test"
.
A son tour, un fichier Gruntfile.js
implémente grunt test
, et peut exécuter une grande variété d'outils et de tests :
eslint
, vérifie les fichiers JS et JSON.stylelint
, vérifie les fichiers CSS et LESS.banana-checker
, vérifie les messages dans les fichiers MediaWiki i18n.
Vous pouvez spécifier les paramètres de configuration pour ces outils dans Gruntfile.js
.
Cependant, il doit contenir un peu ou pas de configuration pour les outils pouvant fonctionner hors de grunt
afin qu'ils fonctionnent de la même manière lorsqu'ils sont exécutés indépendamment ou à partir d'un greffon d'éditeur de texte.
Utiliser toujours les fichiers de configuration natifs quand c'est possible, y compris .eslintrc.json
mentionné ci-dessus.
Documentation JavaScript
Utiliser npm run doc
comme point d'accès.
La convention est d'utiliser JSDoc .
Les accroches predoc
et postdoc
des scripts dans package.json
peuvent être utilisées pour exécuter tout script supplémentaire (par exemple pour construire à l'avance les fichiers pour l'inclusion, ou pour copier des fichiers supplémentaires pour la publication après coup).
Exemples
Configuration avancée utilisant Grunt
package.json
{
"private": true,
"scripts": {
"test": "grunt test"
},
"devDependencies": {
"eslint-config-wikimedia": "0.15.0",
"grunt": "1.0.4",
"grunt-banana-checker": "0.8.1",
"grunt-eslint": "22.0.0",
"grunt-stylelint": "0.12.0",
"stylelint-config-wikimedia": "0.7.0"
}
}
Gruntfile.js
/* eslint-env node, es6 */
module.exports = function ( grunt ) {
grunt.loadNpmTasks( 'grunt-banana-checker' );
grunt.loadNpmTasks( 'grunt-eslint' );
grunt.loadNpmTasks( 'grunt-stylelint' );
grunt.initConfig( {
eslint: {
options: {
extensions: [ '.js', '.json' ],
cache: true
},
all: [
'**/*.{js,json}',
'!{vendor,node_modules}/**'
]
},
stylelint: {
all: [
'**/*.{css,less}',
'!{vendor,node_modules}/**'
]
},
banana: {
all: 'i18n/'
}
} );
grunt.registerTask( 'test', [ 'eslint', 'stylelint', 'banana' ] );
grunt.registerTask( 'default', 'test' );
};
Exemple de projets
- Extension:BoilerPlate possède un
Gruntfile.js
qui exécute jshint, jscs, et banana-checker (pour les fichiersi18n
de MediaWiki). - jquery-client : package.json (jshint, jscs, karma; Grunt n'est pas nécessaire)
- CSSJanus : package.json / Gruntfile.js (jshint, jscs, test du client)
- TemplateData : package.json / Gruntfile.js (jshint, jscs, banana-checker)
Lectures complémentaires
- format package.json sur docs.npmjs.org
- cycle de vie des scripts de paquets sur docs.npmjs.org
PHP
- Utiliser l'extension BoilerPlate comme point de départ pour une nouvelle extension MediaWiki.
- Utiliser la mediawiki-tools-cookiecutter-library pour créer une nouvelle bibliothèque.
Tests PHP
Nous utilisons composer test
comme point d'accès.
Si votre projet possède des fichiers PHP, il doit lister les paquets de l'environnement de test dont il a besoin dans composer.json
sous require-dev
et lister les commandes à exécuter dans la propriété scripts.test
:
{
"require-dev": {
"mediawiki/mediawiki-codesniffer": "44.0.0",
"mediawiki/mediawiki-phan-config": "0.14.0",
"mediawiki/minus-x": "1.1.3",
"ockcyp/covers-validator": "1.6.0",
"php-parallel-lint/php-console-highlighter": "1.0.0",
"php-parallel-lint/php-parallel-lint": "1.4.0",
"phpunit/phpunit": "9.6.16"
},
"scripts": {
"test": [
"parallel-lint . --exclude vendor --exclude node_modules",
"php -d 'extension=pcov.so' vendor/bin/phpunit",
"covers-validator",
"phpcs -sp",
"phan --allow-polyfill-parser --long-progress-bar",
"minus-x check ."
],
"fix": [
"minus-x fix .",
"phpcbf"
]
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
Voir composer.json du projet cdb pour un bon exemple.
Notez que les extensions MediaWiki ne sont pas des projets séparés et ne peuvent pas exécuter leur propres suite de tests PHPUnit depuis Composer.
Ces dépôts ont des tâche mediawiki-extensions
séparées.
PHPCS et PHP lint sont toujours exécutés via composer.json
et composer test
:
{
"require-dev": {
"mediawiki/mediawiki-codesniffer": "44.0.0",
"mediawiki/mediawiki-phan-config": "0.14.0",
"mediawiki/minus-x": "1.1.3",
"php-parallel-lint/php-console-highlighter": "1.0.0",
"php-parallel-lint/php-parallel-lint": "1.4.0"
},
"scripts": {
"test": [
"parallel-lint . --exclude vendor --exclude node_modules",
"phpcs -sp --cache",
"minus-x check ."
],
"fix": [
"minus-x fix .",
"phpcbf"
],
"phan": "phan -d . --long-progress-bar"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
Voir composer.json de l'extension MediaWiki AbuseFilter pour un bon exemple.
Documentation PHP
Voir : Doxygen .
Utiliser le programme doxygen pour générer un fichier Doxyfile
à la racine du project.
Tests Python
Voir les tutoriels sur les tests de Python de l'intégration continue.
Ruby
Rake
Utiliser Rake pour définir vos commandes, elles seront exécutées via Bundler.
Exemple Rakefile
:
require 'bundler/setup'
require 'rubocop/rake_task'
RuboCop::RakeTask.new(:rubocop) do |task|
# si vous utilisez mediawiki-vagrant, rubocop va utiliser par défaut son .rubocop.yml
# la ligne suivante indique explicitement que vous voulez .rubocop.yml du répertoire
# où 'bundle exec rake' est exécuté
task.options = ['-c', '.rubocop.yml']
end
require 'mediawiki_selenium/rake_task'
MediawikiSelenium::RakeTask.new
task default: [:test]
desc 'Run all build/tests commands (CI entry point)'
task test: [:rubocop]
Le code ci-dessus créera les cibles Rake suivantes.
$ bundle exec rake -T rake rubocop # Exécuter RuboCop rake rubocop:auto_correct # Correction automatique des infractions RuboCop rake selenium # Exécuter les fonctions ''Cucumber'' rake test # Exécuter toutes les commandes de construction et de test (point d'entrée de l'intégration continue (CI) )
Le tâche de Jenkins rake-jessie
invoque la cible test
en exécutant bundle exec rake test
.
Référence : phab:T104024
Conseils de debogage ruby
Vous pouvez utiliser le gem pry
pour casser l'erreur et afficher une console dans le contexte de l'échec.
Ajouter gem 'pry'
à votre Gemfile pour ensuite interrompre :
require 'pry'
binding.pry
your call that fail
Vous serez alors dans une console avant la rupture ce qui vous permet d'inspecter l'environnement (ls
).
Voir https://github.com/pry/pry pour les détails.
ci.yml
Nous disposons d'un ensemble de tâches Jenkins qui s'exécutent quotidiennement et qui lancent Ruby avec les tests Selenium .
Les tâches s'appellent selenium*
.
Chaque dépôt ne possède qu'une seule tâche définie dans Jenkins.
Il s'agit d'une tâche multi-configuration qui génère une ou plusieurs tâches filles basées sur une configuration dans chaque dépôt : tests/browser/ci.yml
.
La tâche principale créera des tâches filles en fonction de son contenu.
Exemple simple de ci.yml
dans mediawiki/core
.
BROWSER:
- firefox
MEDIAWIKI_ENVIRONMENT:
- beta
PLATFORM:
- Linux
Comme vous le voyez, il y a trois variables, BROWSER
, MEDIAWIKI_ENVIRONMENT
et PLATFORM
.
BROWSER
et PLATFORM
peuvent être toutes des combinaison de navigateur Sauce Labs/OS/version valides.
MEDIAWIKI_ENVIRONMENT
peut avoir les valeurs beta
, mediawiki
et test
, ou tout autre paramètre configuré dans environments.yml
.
Par exemple :
BROWSER:
- chrome
- firefox
- internet_explorer 9.0
- safari
MEDIAWIKI_ENVIRONMENT:
- beta
- mediawiki
- test
PLATFORM:
- Linux
- OS X 10.9
- Windows 8.1
Exemple d'ci.yml
compliquée dans mediawiki/extensions/MultimediaViewer
.
Pour plus d'informations, voir le greffon Yaml Axis Jenkins.
Référence : phab:T128190