Connecter SonarQube au QE Score : récupère tes premières métriques qualité de code !
- Simon CHAMPENOIS
- 27 mars
- 4 min de lecture
Dernière mise à jour : 23 avr.
Dans cet article, tu vas apprendre à connecter SonarQube au QE Score pour remonter automatiquement les métriques qualité de ton code : nombre de lignes, duplication, test coverage, date de dernier scan, code smells, quality gate, etc. 🚀 En quelques minutes, ton tableau de bord QE Score affichera des données clés issues de ton analyse Sonar !

📺 Vidéo de démo
🧠 En résumé :
Étape | Titre | Durée estimée |
1 | Récupérer la clé du projet Sonar | 5 min |
2 | Générer un token d’accès | 3 min |
3 | Rafraîchir les données depuis QE Score | 1 min |
4 | Vérifier les métriques | 1 min |
5 | Visualiser les résultats dans QE Score | 0 min |
🛠️ Prérequis
✔️ Avoir réalisé la configuration du Data Collection via l’article : 👉 "Télécharge le Quick Start Kit et crée ton 1er QE Score en 30 minutes top chrono !"
✔️ Avoir un projet SonarQube opérationnel avec des données d’analyse.
🔑 Étape 1 – Récupère la clé de ton projet Sonar (⏱️ 5 min)
Connecte-toi à ton projet SonarQube
Clique sur “Information”
Copie la Project Key
📝 Ensuite, dans ton Google Sheet (copie de QEscore_DataCollection_v1.0_starterkit), Onglet repository_settings :
Colonne A ("Product") : nom de ton app (ex: AppTrading)
Colonne B ("RepositoryPath") : chemin Git (ex: /github/monorg/monrepo)
Colonne C ("SonarURL") : base URL Sonar (ex: https://sonar.qescore.com)
Colonne D ("SonarKey") : colle ici la Project Key récupérée 🔑

🔐 Étape 2 – Génére un token Sonar (⏱️ 3 min)
Va dans ton profil utilisateur Sonar
Onglet Sécurité
Clique sur Générer un token
Copie-le sans le perdre !
🧩 Puis, dans ton Google Sheet :
Va dans le menu Extensions > Apps Script
Dans les paramètres du script (Paramètres du projet)
Ajoute une propriété nommée : token_sonar
Colle le token comme valeur
✅ Sauvegarde !

🔄 Étape 3 – Récupère les données Sonar dans QE Score (⏱️ 1 min)
🧠 Dans ton Google Sheet, clique sur le menu QE SCORE > Refresh Data Sonar 📥 Les données sont automatiquement récupérées et affichées dans ton tableau.

🔍 Étape 4 – Vérifie les métriques sur Sonar
Retourne sur ton interface Sonar et va dans l’onglet Overall du projet. ✅ Tu dois y retrouver les mêmes valeurs que dans ton Sheet.

🎉 Étape 5 – Bravo ! Tes premières métriques qualité sont là
Va sur l’onglet QE Score dans ton fichier Google Sheet. Tu verras les données intégrées dans le calcul global du score qualité. Et ce n’est que le début ! 🚀
➕ Étape 6 – Ajoute d'autres projets SonarQube
Tu peux suivre le même processus pour plusieurs projets :
Ajoute de nouvelles lignes dans l’onglet repository_settings
Clique à nouveau sur Refresh Data Sonar
QE Score calcule automatiquement une moyenne par application, même avec plusieurs dépôts Git 👌
🧬 Étape 7 – Personnalise les métriques Sonar récupérées
Tu veux aller plus loin ? Ajoute de nouveaux indicateurs qualité !
Ouvre le script QEscore_Sonar.gs dans Apps Script
Modifie les appels API pour intégrer d'autres métriques (ex: bugs, vulnerabilities, etc.)
Ajoute les colonnes correspondantes dans repository_settings
📌 Attention : le nom des colonnes doit être déclaré en début de script, dans la variable columnIndices.
🧑💻 Le script complet
Voici le script principal pour récupérer automatiquement les données qualité depuis Sonar. Tu peux le copier tel quel ou l’adapter à tes besoins 👇
function QESCORE_getSonar() {
var sheetSettings = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("repository_settings");
var rawSettings = 3;
var headers = sheetSettings.getRange(2, 1, 1, sheetSettings.getLastColumn()).getValues()[0];
var tokenSonar = PropertiesService.getScriptProperties().getProperty('token_sonar');
var columnIndices = {
sonarURL: headers.indexOf("SonarURL"),
sonarKey: headers.indexOf("SonarKey"),
error: headers.indexOf("Error"),
scriptExecution: headers.indexOf("ScriptExecution"),
codeDuplication: headers.indexOf("CodeDuplication"),
codeUnitTestCoverage: headers.indexOf("unitTestCoverage"),
codeQualityGate: headers.indexOf("QualityGate"),
codeSmell: headers.indexOf("CodeSmell"),
scanDate: headers.indexOf("SonarScanDate"),
loc: headers.indexOf("NumLines")
};
var todayHour = getTodayHour();
while (sheetSettings.getRange(rawSettings, columnIndices.sonarKey + 1).getValue() !== "") {
try {
var rowData = sheetSettings.getRange(rawSettings, 1, 1, sheetSettings.getLastColumn()).getValues()[0];
var sonarKey = rowData[columnIndices.sonarKey];
var sonarURL = rowData[columnIndices.sonarURL];
if (!sonarURL || sonarURL.trim() === "") {
throw new Error("Missing SonarURL in sheet for row " + rawSettings);
}
if (!sonarKey || sonarKey.trim() === "") {
rawSettings++;
continue;
}
var encodedToken = Utilities.base64Encode(tokenSonar + ":");
// 1. Duplicated code (%)
var duplicationUrl = `${sonarURL}/api/measures/component?component=${sonarKey}&metricKeys=duplicated_lines_density`;
var duplication = fetchSonarMetric(duplicationUrl, encodedToken, "duplicated_lines_density") / 100;
// 2. Lines of code (ncloc)
var locUrl = `${sonarURL}/api/measures/component?component=${sonarKey}&metricKeys=ncloc`;
var loc = fetchSonarMetric(locUrl, encodedToken, "ncloc");
// 3. Last scan date
var dateUrl = `${sonarURL}/api/project_analyses/search?project=${sonarKey}&ps=1`;
var scanDate = fetchSonarDate(dateUrl, encodedToken);
// 4. Unit test coverage (%)
var coverageUrl = `${sonarURL}/api/measures/component?component=${sonarKey}&metricKeys=coverage`;
var coverage = fetchSonarMetric(coverageUrl, encodedToken, "coverage") / 100;
// 5. Quality Gate status (OK / ERROR)
var qualityGateUrl = `${sonarURL}/api/qualitygates/project_status?projectKey=${sonarKey}`;
var qualityGateStatus = fetchSonarQualityGateStatus(qualityGateUrl, encodedToken);
// 6. Code Smells
var codeSmellUrl = `${sonarURL}/api/measures/component?component=${sonarKey}&metricKeys=code_smells`;
var codeSmells = fetchSonarMetric(codeSmellUrl, encodedToken, "code_smells");
// Writing values to the sheet
sheetSettings.getRange(rawSettings, columnIndices.codeDuplication + 1).setValue(parseFloat(duplication));
sheetSettings.getRange(rawSettings, columnIndices.loc + 1).setValue(parseInt(loc));
sheetSettings.getRange(rawSettings, columnIndices.scanDate + 1).setValue(scanDate);
sheetSettings.getRange(rawSettings, columnIndices.codeUnitTestCoverage + 1).setValue(parseFloat(coverage));
sheetSettings.getRange(rawSettings, columnIndices.codeQualityGate + 1).setValue(qualityGateStatus);
sheetSettings.getRange(rawSettings, columnIndices.codeSmell + 1).setValue(parseInt(codeSmells));
sheetSettings.getRange(rawSettings, columnIndices.scriptExecution + 1).setValue(todayHour);
} catch (e) {
var errorMessage = `${todayHour} - Error: ${e.message}`;
sheetSettings.getRange(rawSettings, columnIndices.error + 1).setValue(errorMessage);
}
rawSettings++;
}
}
// Fetches a specific metric value from SonarCloud API
function fetchSonarMetric(url, encodedToken, metricKey) {
var options = {
'headers': {
'Authorization': 'Basic ' + encodedToken,
'Accept': 'application/json'
}
};
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
return result.component.measures[0].value;
}
// Fetches the date of the last analysis
function fetchSonarDate(url, encodedToken) {
var options = {
'headers': {
'Authorization': 'Basic ' + encodedToken,
'Accept': 'application/json'
}
};
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
var isoDate = result.analyses[0].date;
var parsedDate = new Date(isoDate);
return Utilities.formatDate(parsedDate, Session.getScriptTimeZone(), "dd/MM/yyyy HH:mm");
}
// Fetches the Quality Gate status (OK, ERROR, etc.)
function fetchSonarQualityGateStatus(url, encodedToken) {
var options = {
'headers': {
'Authorization': 'Basic ' + encodedToken,
'Accept': 'application/json'
}
};
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
var status = result.projectStatus.status;
return status === "OK" ? "PASSED" : "FAILED";
}
function getTodayHour() {
return Utilities.formatDate(new Date(), SpreadsheetApp.getActive().getSpreadsheetTimeZone(), "dd/MM/yyyy HH:mm");
}
Comments