Intégration continue/Points d'entrée

This page is a translated version of the page Continuous integration/Entry points and the translation is 100% complete.

Nous avons standardisé les tests de notre code sur les outils suivants :

Langage Lanceur de commande Contrôle du code Style du code Analyse statique Tests unitaires Documentation
PHP composer php-parallel-lint

php -l

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.

Dans les anciennes formes Linux, si les commandes 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

Utiliser l'extension BoilerPlate pour commencer une nouvelle extension MediaWiki.

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

Lectures complémentaires

PHP

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

Notes