kopia lustrzana https://github.com/badgen/badgen.net
feat: Added badge endpoint for Jenkins jobs (#418)
* feat: Added badge endpoint for Jenkins jobs * fix: Removed unused variable * Update api/jenkins.ts Co-authored-by: Amio Jin <amio.cn@gmail.com> Co-authored-by: Amio Jin <amio.cn@gmail.com>pull/420/head
rodzic
d5cbde60ce
commit
defdbb9dcd
|
@ -0,0 +1,108 @@
|
||||||
|
import got from "../libs/got";
|
||||||
|
import { createBadgenHandler, PathArgs } from "../libs/create-badgen-handler";
|
||||||
|
import humanizeDuration from "humanize-duration";
|
||||||
|
|
||||||
|
export default createBadgenHandler({
|
||||||
|
title: "Jenkins",
|
||||||
|
examples: {
|
||||||
|
"/jenkins/last-build/jenkins.mono-project.com/job/test-mono-mainline/":
|
||||||
|
"Last build status",
|
||||||
|
"/jenkins/fix-time/jenkins.mono-project.com/job/test-mono-mainline/":
|
||||||
|
"Time taken to fix a broken build",
|
||||||
|
"/jenkins/broken-build/jenkins.mono-project.com/job/test-mono-mainline/":
|
||||||
|
"# of broken builds",
|
||||||
|
},
|
||||||
|
handlers: {
|
||||||
|
"/jenkins/last-build/:hostname/:job*": lastJobStatusHandler,
|
||||||
|
"/jenkins/fix-time/:hostname/:job*": buildFixTimeHandler,
|
||||||
|
"/jenkins/broken-build/:hostname/:job*": brokenBuildsHandler,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const shortEnglishHumanizer = humanizeDuration.humanizer({
|
||||||
|
language: "shortEn",
|
||||||
|
units: ["d", "h"],
|
||||||
|
round: true,
|
||||||
|
languages: {
|
||||||
|
shortEn: {
|
||||||
|
y: () => "y",
|
||||||
|
mo: () => "mo",
|
||||||
|
w: () => "w",
|
||||||
|
d: () => "d",
|
||||||
|
h: () => "h",
|
||||||
|
m: () => "m",
|
||||||
|
s: () => "s",
|
||||||
|
ms: () => "ms",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const statusToColor = (status: string) => {
|
||||||
|
return status.toUpperCase() === "SUCCESS" ? "green" : "red";
|
||||||
|
};
|
||||||
|
|
||||||
|
const brokenBuildsToColor = (count: number) => {
|
||||||
|
return count < 10 ? "green" : count < 20 ? "orange" : "red";
|
||||||
|
};
|
||||||
|
const buildFixTimeToColor = (hours: number) => {
|
||||||
|
return hours < 2 ? "green" : hours < 6 ? "orange" : "red";
|
||||||
|
};
|
||||||
|
|
||||||
|
async function jenkinsLastBuild({ hostname, job }: PathArgs) {
|
||||||
|
const endpoint = `https://${hostname}/${job}/lastBuild/api/json?tree=result,timestamp,estimatedDuration`;
|
||||||
|
return await got(endpoint).json<any>();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function jenkinsBuilds({ hostname, job }: PathArgs) {
|
||||||
|
const endpoint = `https://${hostname}/${job}/api/json?tree=builds[number,status,timestamp,id,result]`;
|
||||||
|
return await got(endpoint).json<any>();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function lastJobStatusHandler({ hostname, job }: PathArgs) {
|
||||||
|
const response = await jenkinsLastBuild({ hostname, job });
|
||||||
|
return {
|
||||||
|
subject: "Last Build",
|
||||||
|
status: response.result,
|
||||||
|
color: statusToColor(response.result),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function brokenBuildsHandler({ hostname, job }: PathArgs) {
|
||||||
|
const response = await jenkinsBuilds({ hostname, job });
|
||||||
|
const brokenBuilds = response.builds.filter(function (build) {
|
||||||
|
return build.result.toUpperCase() !== "SUCCESS";
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
subject: "Broken Builds",
|
||||||
|
status: brokenBuilds.length,
|
||||||
|
color: brokenBuildsToColor(brokenBuilds.length),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildFixTimeHandler({ hostname, job }: PathArgs) {
|
||||||
|
const response = await jenkinsBuilds({ hostname, job });
|
||||||
|
|
||||||
|
var lastSuccessTime = 0;
|
||||||
|
var lastFailTime = 0;
|
||||||
|
|
||||||
|
for (let index = 0; index < response.builds.length; index++) {
|
||||||
|
const element = response.builds[index];
|
||||||
|
if (element.result.toUpperCase() == "SUCCESS") {
|
||||||
|
lastSuccessTime = element.timestamp;
|
||||||
|
lastFailTime = lastSuccessTime;
|
||||||
|
} else {
|
||||||
|
lastFailTime = element.timestamp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastSuccessTime == 0) lastSuccessTime = new Date().getTime();
|
||||||
|
if (lastFailTime == 0) lastFailTime = lastSuccessTime;
|
||||||
|
|
||||||
|
return {
|
||||||
|
subject: "Fix Time",
|
||||||
|
status: `${shortEnglishHumanizer((lastSuccessTime - lastFailTime) | 0)}`,
|
||||||
|
color: buildFixTimeToColor(
|
||||||
|
((lastSuccessTime - lastFailTime) / 3600000) | 0
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
|
@ -58,6 +58,7 @@ export const liveBadgeList = [
|
||||||
'tidelift',
|
'tidelift',
|
||||||
'runkit',
|
'runkit',
|
||||||
'https',
|
'https',
|
||||||
|
'jenkins',
|
||||||
]
|
]
|
||||||
|
|
||||||
export async function loadBadgeMeta () {
|
export async function loadBadgeMeta () {
|
||||||
|
|
|
@ -4861,9 +4861,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"elliptic": {
|
"elliptic": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
|
||||||
"integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
|
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "^4.4.0",
|
"bn.js": "^4.4.0",
|
||||||
|
@ -6114,6 +6114,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"humanize-duration": {
|
||||||
|
"version": "3.23.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.23.1.tgz",
|
||||||
|
"integrity": "sha512-aoOEkomAETmVuQyBx4E7/LfPlC9s8pAA/USl7vFRQpDjepo3aiyvFfOhtXSDqPowdBVPFUZ7onG/KyuolX0qPg=="
|
||||||
|
},
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
@ -7114,9 +7119,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
|
@ -7203,12 +7208,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"move-concurrently": {
|
"move-concurrently": {
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"date-fns": "^2.15.0",
|
"date-fns": "^2.15.0",
|
||||||
"got": "^10.7.0",
|
"got": "^10.7.0",
|
||||||
"haxe-rpc-client": "^1.0.0",
|
"haxe-rpc-client": "^1.0.0",
|
||||||
|
"humanize-duration": "^3.23.1",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"measurement-protocol": "^0.1.1",
|
"measurement-protocol": "^0.1.1",
|
||||||
"micro": "^9.3.4",
|
"micro": "^9.3.4",
|
||||||
|
|
Ładowanie…
Reference in New Issue