Hello Antichesse, tu m'as dit que tu allais peut-être t'intéresser à la remontée du coverage côté Front vers Sonar, donc je te met des infos sur ce que j'ai fait, pour t'aider.
Infos préalables (mais je sais que ça marche avec Angular et depuis Karma 4.1.0) :
Package.json
"devDependencies": {
"@angular-devkit/build-angular": "0.901.0",
"@angular/cli": "9.1.0",
"@angular/compiler-cli": "9.1.0",
"@angular/language-service": "9.1.0",
"@types/jasmine": "3.5.10",
"@types/jasminewd2": "2.0.8",
"@types/node": "12.12.34",
"codelyzer": "5.2.2",
"jasmine-core": "3.5.0",
"jasmine-spec-reporter": "4.2.1",
"karma": "4.4.1",
"karma-coverage-istanbul-reporter": "2.1.1",
"karma-firefox-launcher": "1.3.0",
"karma-jasmine": "3.0.3",
"karma-jasmine-html-reporter": "1.5.3",
"protractor": "5.4.3",
"ts-node": "8.3.0",
"tslint": "6.1.1",
"typescript": "3.8.3"
},
Alors déjà, je lance mes tests en Firefox Headless.
Extrait de mon fichier Karma.conf.js :
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-firefox-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
...
browsers: ['FirefoxHeadless'],
captureTimeout: 600000,
browserDisconnectTolerance: 3,
browserDisconnectTimeout: 600000,
browserNoActivityTimeout: 600000,
customLaunchers: {
FirefoxHeadless: {
base: 'Firefox',
flags: ['-headless', '--no-sandbox']
}
}
...
});
};
Mais surtout, dans le fichier Karma, il y a un élément super important, l'emplacement de stockage de ton coverage :
Karma.conf.js
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/project-name'), **<---- ICI**
reports: ['html', 'lcovonly', 'text-summary'], <--- Lcov doit être inclu aussi !
fixWebpackSourcePaths: true
},
Le dir indique ou le coverage sera stocké. Tu en auras besoin dans ton fichier JenkinsFile. Pour moi, à la racine de mon WORKSPACE, j'aurais un dossier "coverage", qui contient un autre dossier "project-name" contenant le résultat de l'analyse Istanbul-reporter, incluant le coverage.
Voici quelques extraits de mon fichier JenkinsFile, pour montrer les modifs que j'ai du faire :
pipeline {
agent { label 'trololo-pouetpouet' }
stages {
stage('Clone source code') {
steps {
git branch:'${BRANCH_NAME}', credentialsId: gitCredentialsId, url: gitSshUrl
}
}
stage('Test') {
steps {
println " ========== START PLAYING TESTS ========== "
configFileProvider([configFile(fileId: 'npm-npmrc', targetLocation: '/root/.npmrc')]) {
sh "export SASS_BINARY_PATH=${sassBinaryLocation}/${bindingNodeFileName} ; npm run test-prod"
}
stash includes: 'coverage/**/*', name: 'COVERAGE' **<---- Ici, c'est parce que je change d'agent, donc je garde l'output de mon coverage **
}
}
stage('Build') {
steps {
println " ========== START BUILDING DELIVERABLE ========== "
...
}
}
stage('Sonarqube analysis') {
agent {
label 'sonar-scanner-agent-de-ouf'
}
steps {
git branch:'${BRANCH_NAME}', credentialsId: gitCredentialsId, url: gitSshUrl
script {
configFileProvider([configFile(fileId: 'npm-npmrc', targetLocation: '/root/.npmrc')]) {
...
unstash 'COVERAGE' ** <----- je récupère mon output d'analyse incluant mon coverage **
withSonarQubeEnv(sonarEnvName) {
sh "sonar-scanner "+
"-Dsonar.verbose=true "+
"-Dsonar.projectBaseDir=${WORKSPACE} "+
"-Dsonar.projectVersion=${taggedVersion} "+
"-Dsonar.sources=. "+
"-Dsonar.exclusions='**/*.spec.ts, **/*.js, src/test/*'"+ **<---- Ici, j'exclue les tests et le js du coverage et de l'analyse **
"-Dsonar.projectName='${binaryName}' "+
"-Dsonar.projectKey=${binaryName} "+
"-Dsonar.typescript.lcov.reportPaths=${env.WORKSPACE}/coverage/project-name/lcov.info "+ <---- Ici, il faut indiquer le path récupéré depuis le fichier Karma.conf.js, et pointer vers le fichier lcov.info
(env.BRANCH_NAME != 'master' ? "-Dsonar.branch.name=${env.BRANCH_NAME} -X " : "")
}
}
}
}
}
...
}
...
}
Et last, but not least, une petite indication supplémentaire à préciser quand on fait de l'angular :
package.json
"scripts": {
"ng": "ng",
...
"test": "ng test --watch --code-coverage", ** <---- Indiquer que l'on veut l'emission du coverage !**
"test-prod": "npm install && ng test --code-coverage",
"lint": "ng lint",
"e2e": "ng e2e"
},
Note : l'option de script "--code-coverage" peut également être remplacée par l'option de build:
"test": { ** <---- En phase test **
"builder": ...
"options": {
....
"codeCoverage": true, ** <---- Indiquer codeCoverage true **
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss",
....
}
},
Et voilà, ton coverage est dispo sur SONAR !
Si quelque n'est pas clair, n'hésite pas à me le dire !
Bon, même si je ne vois pas encore d'intérêt technique à cette façon de faire, je note l'article.
J'ai lu avec attention l'article.
J'ai du mal à sérieusement considérer une solution qui passerait par des iFrame...
Pour moi, ça n'est pas la bonne solution.
Encore une fois, la personne qui a écrit ça s'est concentré sur l'organisation des équipes autour de l'output. Je verrai plutôt à me demander comment gérer une équipe autour d'un travail.
Le problème avec les équipes autonomes sur des périmètres restreints, c'est le SILO. Donc, à mon sens, c'est un non-sens que de vouloir créer encore plus d'équipe en autarcie au sein d'une même application. Il faut une SEULE équipe autonome, qui se répartit le travail sur les différents morceaux.
1 tâche => 1 poste, at scale, ça fait : 1 segment => 1 équipe... Taylorisme, quand tu nous tiens...
Mais le silo a cet avantage certain qu'il nous évite d'avoir à communiquer et collaborer avec les autres. C'est très confortable quand on ne choisit pas ses collègues.
Je préfère la solution de Audrey Neveu consistant à inclure une lib dans une SPA, qui gère le menu.
Une propal de micro-front. On découpe le front avec les micro services et on les insère dans un "portail".
Premier essai via web-components :
Les pours :
- Look and feel consistant
- Plusieurs composants sur la même page
- Indépendant au niveau déploiement entre les composants
Les contres :
- Pas une SPA (on recharge tout à chaque fois)
- Mauvaises performances (notamment duplication librairies)
- Dépendances entre SPA qui rentrent en conflit.
- Mécanisme de routing (basé sur les #) : A redéfinir totalement pour éviter les conflits : conflit entre apps
- Installation de la stack lourd (surtout en local pour du test)
Second essai via les React Fragments (avec Tailor pour résoudre les temps différents de réponse entre les différentes applications) :
Les pours :
- Possibilité de partager des composants réact entiers
- Système de routage centralisé
Les contres :
- Dépendances entre libs : toujours un pb
- Dépendances de Réact encore plus problématiques
Troisième essai avec Layout-as-lib (c'est Layout-as-lib qui est la librairie qui s'inscrit dans les applications). Layout-as-lib est masqué par défaut pour la version "legacy" et affichée en cas de besoin dans les différentes SPA.
Les pours :
- Plus facile d'utiliser une lib dans une SPA que l'inverse : Intégration en 1,5 jour
- Plus rapide
- Indépendance dans le développement et le déploiement : on release chaque SPA distinctement
- Plus de conflit de librairie
- On ne peut continuer à tester que son composant
Les contres :
- Pas de SPA du tout (mais c'est pas grave dans leur cas)
- Pas de possibilité d'aggregation de composants (mais c'est pas grave dans leur cas)
- Expérience utilisateur peut être incohérente : Une SPA n'a pas l'appel à la lib à la même version que l'autre SPA
- Des changements majeurs dans la navigation doivent être reportés partout
L'idée est hyper intéressante : On garde le concept de SPA, mais on rajoute des éléments de navigation entre SPA via une logique de lib.
J'aime bien ! Je valide à 100% l'idée ! C'est super génial !
!! Points d'attention !! :
- Bien réfléchir son usecase d'abord
- Attention au design (style - Css)