diff --git a/bin/pipelines.js b/bin/pipelines.js new file mode 100644 index 0000000..bb4dda6 --- /dev/null +++ b/bin/pipelines.js @@ -0,0 +1,138 @@ +const { LogType } = require("loguix") +const fs = require("fs") +const path = require("path") +const { __glob } = require("./global-variables") +const clog = new LogType("Pïpeline") +const config = require("./config") + +const tokenkey = config.getFile().JENKINS_TOKEN + +module.exports.getAllPipelines = function() { + + return new Promise((resolve, reject) => { + + + fetch(`https://jenkins.raphix.fr/api/json`, { + method: "GET", + headers: { + "Accept": "application/json", + "Authorization": `Basic ${tokenkey}` + }, + credentials: "include" + }) + .then(res => res.json()) + .then(async list => { + + const pipelinesJobs = new Array() + + for(const job of list.jobs) { + await fetch(`${job.url}/api/json`, { + method: "GET", + headers: { + "Accept": "application/json", + "Authorization": `Basic ${tokenkey}` + }, + credentials: "include" + }) + .then(res => res.json()) + .then(async res => { + + if(res._class == "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject") { + await getJobMain(res).then(resJ => { + res.jobs[0] = resJ + pipelinesJobs.push(res) + }) + } else { + pipelinesJobs.push(res) + + } + + + }) + } + + list.jobs = pipelinesJobs + + resolve(list) + + + }) + .catch(err => { + resolve("UNAVAILABLE") + }) + }) + + +} + +module.exports.startPipeline = function(pipeline) { + + +// If it's a freestyle job, build with params + + if(pipeline.type == "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject") { + return new Promise((resolve, reject) => { + fetch(`${pipeline.url}/job/${pipeline.jobname}/build?delay=0sec`, { + method: "POST", + headers: { + "Authorization": `Basic ${tokenkey}` + }, + credentials: "include" + }) + .then(res => { + resolve("OK") + }) + }) + } else { + return new Promise((resolve, reject) => { + + const parameters = pipeline.fields + + const formatedParams = new URLSearchParams() + + for(const param of parameters) { + formatedParams.append(param.name, param.value) + } + + + + + fetch(`${pipeline.url}/buildWithParameters?delay=0sec`, { + method: "POST", + headers: { + "Authorization": `Basic ${tokenkey}`, + "Content-Type": "application/x-www-form-urlencoded" + }, + credentials: "include", + body: formatedParams + }) + .then(res => { + resolve("OK") + }) + }) + } + + + +} + +function getJobMain(res) { + + return new Promise(async (resolve, reject) => { + + await fetch(`${res.jobs[0].url}/api/json`, { + method: "GET", + headers: { + 'Accept': 'application/json', + 'Authorization': `Basic ${tokenkey}` + }, + credentials: 'include' + }).then(res => res.json()) + .then(res => { + resolve(res) + }) + + + }) + +} diff --git a/bin/servers.js b/bin/servers.js index cf72414..1de066e 100644 --- a/bin/servers.js +++ b/bin/servers.js @@ -6,6 +6,7 @@ const auth = require("./auth.js") const files = require("./files.js") const links = require("./links.js") const service = require("./services.js") +const pipeline = require("./pipelines.js") const plog = new LogType("Web") const cook = require("cookie") const http = require("http") @@ -49,56 +50,56 @@ module.exports.serverIO = function(server) { if(user.checkPermission("FILES_EXPLORER")) { - PostRequest("FX_GET", (root) => { + PostRequest("FX_GET", (root) => { - PostAnswer("FX_GET", files.getFiles(root)) - }) + PostAnswer("FX_GET", files.getFiles(root)) + }) - PostRequest("FX_NEW_FOLDER", (root) => { + PostRequest("FX_NEW_FOLDER", (root) => { - PostAnswer("FX_NEW_FOLDER", files.createFolder(root)) - }) + PostAnswer("FX_NEW_FOLDER", files.createFolder(root)) + }) - PostRequest("FX_DELETE", (root) => { + PostRequest("FX_DELETE", (root) => { - PostAnswer("FX_DELETE", files.deleteFile(root)) - } ) + PostAnswer("FX_DELETE", files.deleteFile(root)) + } ) - PostRequest("FX_RENAME", (settings) => { - - PostAnswer("FX_RENAME", files.renameFile(settings)) - }) - - PostRequest("FX_SHARE", (settings) => { + PostRequest("FX_RENAME", (settings) => { - PostAnswer("FX_SHARE", files.shareFile(settings)) - }) + PostAnswer("FX_RENAME", files.renameFile(settings)) + }) - PostRequest("FX_GETFILE", (root) => { - - PostAnswer("FX_GETFILE", files.getFile(root)) - }) + PostRequest("FX_SHARE", (settings) => { + + PostAnswer("FX_SHARE", files.shareFile(settings)) + }) - PostRequest("FX_SAVEFILE", (settings) => { - - PostAnswer("FX_SAVEFILE", files.saveFile(settings)) - }) - - PostRequest("FX_NEW_FILE", (settings) => { + PostRequest("FX_GETFILE", (root) => { - PostAnswer("FX_NEW_FILE", files.newFile(settings)) - }) - - PostRequest("FX_UPLOAD", (settings) => { + PostAnswer("FX_GETFILE", files.getFile(root)) + }) - PostAnswer("FX_UPLOAD", files.uploadFile(settings)) + PostRequest("FX_SAVEFILE", (settings) => { + + PostAnswer("FX_SAVEFILE", files.saveFile(settings)) + }) - }) + PostRequest("FX_NEW_FILE", (settings) => { + + PostAnswer("FX_NEW_FILE", files.newFile(settings)) + }) + + PostRequest("FX_UPLOAD", (settings) => { - PostRequest("FX_PASTE", (settings) => { - - PostAnswer("FX_PASTE", files.pasteFile(settings)) - }) + PostAnswer("FX_UPLOAD", files.uploadFile(settings)) + + }) + + PostRequest("FX_PASTE", (settings) => { + + PostAnswer("FX_PASTE", files.pasteFile(settings)) + }) } @@ -151,6 +152,17 @@ module.exports.serverIO = function(server) { }); } + if(user.checkPermission("PIPELINES")) { + GetRequest("PL_GET_ALL", async () => { + GetAnswer("PL_GET_ALL", await pipeline.getAllPipelines()) + }) + + PostRequest("PL_START", async (settings) => { + PostAnswer("PL_START", await pipeline.startPipeline(settings)) + }) + + } + socket.on("disconnect", () => { plog.log("Déconnexion du panel par '" + user.username + "' avec le socket : " + socket.id) diff --git a/package.json b/package.json index 1a2d616..88fab00 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "neutral", - "version": "0.4.0", + "version": "0.5.0", "description": "Panel d'administration de Raphix", "main": "index.js", "scripts": { diff --git a/public/javascripts/basics.js b/public/javascripts/basics.js index 4c9b221..8164812 100644 --- a/public/javascripts/basics.js +++ b/public/javascripts/basics.js @@ -201,6 +201,7 @@ class ViewWindow { let offsetX, offsetY; windowDiv.style.zIndex = zIndex + 1 + header.addEventListener('mousedown', (e) => { isDragging = true; @@ -244,6 +245,8 @@ class ViewWindow { this.ViewItem.show() + + } destroy() { @@ -577,12 +580,14 @@ class Service { url = null canAccess = false isOnline = false + View = null constructor(properties) { this.name = properties.name this.description = properties.description this.icon = properties.icon this.url = properties.url this.canAccess = properties.canAccess + this.View = properties.View } generateHTML() { @@ -633,7 +638,7 @@ class Service { // Make a popup of View to select if you want to start, stop or restart the service by doing a request powerButton.addEventListener("click", () => { - View.createPopup({ + this.View.createPopup({ title: ` Gestion de l'alimentation du service`, content: ` @@ -650,7 +655,7 @@ class Service { const startButton = getID(`${this.name}_start`) const stopButton = getID(`${this.name}_stop`) const restartButton = getID(`${this.name}_restart`) - const info = new InfoPop("sv-power-info") + const info = new TextResponse("sv-power-info") @@ -670,7 +675,7 @@ class Service { request.then((answer) => { if(answer.answer == "OK") { statusSpan.innerHTML = ' En ligne' - View.destroyPopup("` Gestion de l'alimentation du service`") + this.View.destroyPopup("` Gestion de l'alimentation du service`") this.isOnline = true } else { info.err("Impossible de démarrer le service") @@ -687,7 +692,7 @@ class Service { if(answer.answer == "OK") { statusSpan.innerHTML = ' Hors ligne' this.isOnline = false - View.destroyPopup("` Gestion de l'alimentation du service`") + this.View.destroyPopup("` Gestion de l'alimentation du service`") } else { info.err("Impossible d'arrêter le service") @@ -706,7 +711,7 @@ class Service { request.then((answer) => { if(answer.answer == "OK") { statusSpan.innerHTML = ' En ligne' - View.destroyPopup("` Gestion de l'alimentation du service`") + this.View.destroyPopup("` Gestion de l'alimentation du service`") this.isOnline = true } else { info.err("Impossible de redémarrer le service") @@ -724,6 +729,227 @@ class Service { } +/** + * Permet de créer un composant de vue de type "Pipeline" + * @param {object} properties Propriétés du composant de vue + */ + +class Pipeline { + name; + pipe; + class; + url; + View; + constructor(properties) { + this.name = properties.pipeline.name + this.class = properties.pipeline._class + this.url = properties.pipeline.url + this.pipe = properties.pipeline + this.View = properties.View + + if(!this.pipe.description) { + this.pipe.description = "Aucune description" + } + } + + generateHTML() { + var image = null + var classInfo = null + var lastBuildStatus = "" + + if(this.class == "hudson.model.FreeStyleProject") { + image = `` + + if(this.pipe.lastBuild) { + lastBuildStatus = `
Construction en cours ... - N°${this.pipe.nextBuildNumber - 1}
` + if(this.pipe.lastSuccessfulBuild) { + if(this.pipe.lastSuccessfulBuild.number == this.pipe.nextBuildNumber - 1) { + lastBuildStatus = `Dernière construction réussie - N°${this.pipe.nextBuildNumber - 1}
` + } + + } + if(this.pipe.lastFailedBuild) { + if(this.pipe.lastFailedBuild.number == this.pipe.nextBuildNumber - 1) { + lastBuildStatus = `Dernière construction échouée - N°${this.pipe.nextBuildNumber - 1}
` + } + + } + + + } else { + lastBuildStatus = `Aucune construction
` + } + + + // TRUE : lastBuildStatus = `Dernière construction réussie - N°${this.pipe.jobs[0].lastSuccessfulBuild.number}
` + // BUILDING : lastBuildStatus = `Construction en cours ... - N°${this.pipe.nextBuildNumber - 1}
` + // FAILED : lastBuildStatus = `Dernière construction échouée - N°${this.pipe.jobs[0].nextBuildNumber - 1}
` + // NOITHING : lastBuildStatus = `Aucune construction
` + } else { + + image = `` + if(this.pipe.jobs[0].lastBuild) { + lastBuildStatus = `Construction en cours ... - N°${this.pipe.jobs[0].nextBuildNumber - 1}
` + if(this.pipe.jobs[0].lastSuccessfulBuild) { + if(this.pipe.jobs[0].lastSuccessfulBuild.number == this.pipe.jobs[0].nextBuildNumber - 1) { + lastBuildStatus = `Dernière construction réussie - N°${this.pipe.jobs[0].nextBuildNumber - 1}
` + } + + } + if(this.pipe.jobs[0].lastFailedBuild) { + if(this.pipe.jobs[0].lastFailedBuild.number == this.pipe.jobs[0].nextBuildNumber - 1) { + lastBuildStatus = `Dernière construction échouée - N°${this.pipe.jobs[0].nextBuildNumber - 1}
` + } + + } + + + } else { + lastBuildStatus = `Aucune construction
` + } + + + + } + + return ` + + ` + } + + + loadScript() { + + const powerButton = getID(`${this.name}_pipelinepower`) + + powerButton.addEventListener("click", () => { + if(this.class == "hudson.model.FreeStyleProject" && this.pipe.property[0].parameterDefinitions.length > 0) { + + var allProperties = new Array() + + for(const property of this.pipe.property[0].parameterDefinitions) { + console.log(property) + if(property.type == "StringParameterDefinition") { + allProperties.push("" + property.name + "
") + } + if(property.type == "ChoiceParameterDefinition") { + + var options = new Array() + for(const option of property.choices) { + options.push(``) + } + + allProperties.push("" + property.name + "
") + } + } + + + + this.View.createPopup({ + title: ` Démarrer la pipeline`, + content: ` + +${this.name}
+ + + + ` + }) + + const startButton = getID(`${this.name}_start`) + const info = new TextResponse("pl-power-info") + + startButton.addEventListener("click", () => { + info.clear() + + + var allFields = new Array() + + for(const property of this.pipe.property[0].parameterDefinitions) { + + + if(getID(property.name).value == "") { + info.err("Veuillez remplir tous les champs") + return + } + allFields.push({name: property.name,value: getID(property.name).value} ) + + } + + const request = post(`PL_START`, {name: this.name, fields: allFields, url: this.url, type: this.class}) + + request.then((answer) => { + + if(answer == "OK") { + info.info("La pipeline a été démarrée avec succès") + this.View.destroyPopup() + + } else { + info.err("Impossible de démarrer la pipeline") + + } + }) + + }) + + + + } else { + + // Open a confirmation popup to start the pipeline + + this.View.createPopup({ + title: ` Démarrer la pipeline`, + content: ` + +${this.name}
+ + + ` + }) + + const startButton = getID(`${this.name}_start`) + const info = new TextResponse("pl-power-info") + + startButton.addEventListener("click", () => { + info.clear() + const request = post(`PL_START`, {name: this.name, url: this.url, type: this.class, jobname: this.pipe.jobs[0].name}) + + request.then((answer) => { + console.log(answer) + if(answer == "OK") { + info.info("La pipeline a été démarrée avec succès") + this.View.destroyPopup() + + } else { + info.err("Impossible de démarrer la pipeline") + + } + }) + + }) + + } + }) + } + +} + /** * Permet de créer un item de la barre des tâches diff --git a/public/javascripts/indexscript.js b/public/javascripts/indexscript.js index 5441228..733680c 100644 --- a/public/javascripts/indexscript.js +++ b/public/javascripts/indexscript.js @@ -2,7 +2,7 @@ const infoUsername = getID("infoUsername") const infoUserimage = getID("infoUserimage") const infoDisplayname = getID("infoDisplayname") const views = getID("views") - +const panelBox = getID("panel-box") // User Request @@ -32,8 +32,10 @@ REQ_user.then((ANS_user) => { if(AvailableViews.join("") == "") { - AvailableViews.push(" Aucune permission ne semble vous êtes accordée
Demandez à Raphix afin de résoudre ce problème
Aucune permission ne semble vous êtes accordée
Demandez à Raphix afin de résoudre ce problème
Chargement en cours ...
+Chargement en cours ...
+Une erreur est survenue lors du chargement des pipelines
+Neutral
Aucune permission ne semble vous êtes accordée
Demandez à Raphix afin de résoudre ce problème