Fixed caching for Jenkins, added enumeration of Firmware view
parent
0598da14c9
commit
402863837c
|
@ -389,6 +389,15 @@
|
||||||
"message" : "Running - OS: <strong>{{operatingSystem}}</strong>, Chrome: <strong>{{chromeVersion}}</strong>, Configurator: <strong>{{configuratorVersion}}</strong>",
|
"message" : "Running - OS: <strong>{{operatingSystem}}</strong>, Chrome: <strong>{{chromeVersion}}</strong>, Configurator: <strong>{{configuratorVersion}}</strong>",
|
||||||
"description": "Message that appears in the GUI log panel indicating operating system, Chrome version and Configurator version"
|
"description": "Message that appears in the GUI log panel indicating operating system, Chrome version and Configurator version"
|
||||||
},
|
},
|
||||||
|
"buildServerLoaded": {
|
||||||
|
"message" : "Loaded builds information for $1 from build server."
|
||||||
|
},
|
||||||
|
"buildServerLoadFailed": {
|
||||||
|
"message" : "<b>Build server query for $1 releases failed, using cached information. Reason: <code>$2</code></b>"
|
||||||
|
},
|
||||||
|
"buildServerUsingCached": {
|
||||||
|
"message" : "Using cached builds information for $1."
|
||||||
|
},
|
||||||
"releaseCheckLoaded": {
|
"releaseCheckLoaded": {
|
||||||
"message" : "Loaded release information for $1 from GitHub."
|
"message" : "Loaded release information for $1 from GitHub."
|
||||||
},
|
},
|
||||||
|
@ -2242,7 +2251,7 @@
|
||||||
"message": "Baud Rate"
|
"message": "Baud Rate"
|
||||||
},
|
},
|
||||||
"firmwareFlasherShowDevelopmentReleases":{
|
"firmwareFlasherShowDevelopmentReleases":{
|
||||||
"message": "Show unstable releases"
|
"message": "Show unstable and additional releases"
|
||||||
},
|
},
|
||||||
"firmwareFlasherShowDevelopmentReleasesDescription":{
|
"firmwareFlasherShowDevelopmentReleasesDescription":{
|
||||||
"message": "Show Release-Candidates and Development Releases."
|
"message": "Show Release-Candidates and Development Releases."
|
||||||
|
|
|
@ -1,66 +1,118 @@
|
||||||
'use strict;'
|
'use strict;'
|
||||||
|
|
||||||
var JenkinsLoader = function (url, jobName) {
|
var JenkinsLoader = function (url) {
|
||||||
var self = this;
|
this._url = url;
|
||||||
|
this._jobs = [];
|
||||||
|
this._cacheExpirationPeriod = 3600 * 1000;
|
||||||
|
|
||||||
self._url = url;
|
this._jobsRequest = '/api/json?tree=jobs[name]';
|
||||||
self._jobName = jobName;
|
this._buildsRequest = '/api/json?tree=builds[number,result,timestamp,artifacts[relativePath],changeSet[items[commitId,msg]]]';
|
||||||
self._jobUrl = self._url + '/job/' + self._jobName;
|
|
||||||
self._buildsRequest = '/api/json?tree=builds[number,result,timestamp,artifacts[relativePath],changeSet[items[commitId,msg]]]';
|
|
||||||
self._builds = {};
|
|
||||||
|
|
||||||
self._buildsDataTag = `${self._jobUrl}BuildsData`;
|
|
||||||
self._cacheLastUpdateTag = `${self._jobUrl}BuildsLastUpdate`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JenkinsLoader.prototype.loadBuilds = function (callback) {
|
JenkinsLoader.prototype.loadJobs = function (viewName, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
chrome.storage.local.get([self._cacheLastUpdateTag, self._buildsDataTag], function (result) {
|
var viewUrl = `${self._url}/view/${viewName}`;
|
||||||
var buildsDataTimestamp = $.now();
|
var jobsDataTag = '${viewUrl}JobsData';
|
||||||
var cachedBuildsData = result[self._buildsDataTag];
|
var cacheLastUpdateTag = '${viewUrl}JobsLastUpdate';
|
||||||
var cachedBuildsLastUpdate = result[self._cacheLastUpdateTag];
|
|
||||||
|
|
||||||
if (!cachedBuildsData || !cachedBuildsLastUpdate || buildsDataTimestamp - cachedBuildsLastUpdate > 3600 * 1000) {
|
var wrappedCallback = jobs => {
|
||||||
var request = self._jobUrl + self._buildsRequest;
|
self._jobs = jobs;
|
||||||
|
callback(jobs);
|
||||||
|
};
|
||||||
|
|
||||||
$.get(request, function (buildsInfo) {
|
chrome.storage.local.get([cacheLastUpdateTag, jobsDataTag], function (result) {
|
||||||
// filter successful builds
|
var jobsDataTimestamp = $.now();
|
||||||
self._builds = buildsInfo.builds.filter(build => build.result == 'SUCCESS')
|
var cachedJobsData = result[jobsDataTag];
|
||||||
.map(build => ({
|
var cachedJobsLastUpdate = result[cacheLastUpdateTag];
|
||||||
number: build.number,
|
|
||||||
artifacts: build.artifacts.map(artifact => artifact.relativePath),
|
|
||||||
changes: build.changeSet.items.map(item => '* ' + item.msg).join('<br>\n'),
|
|
||||||
date: new Date(build.timestamp)
|
|
||||||
}));
|
|
||||||
|
|
||||||
self._parseBuilds(callback);
|
if (!cachedJobsData || !cachedJobsLastUpdate || jobsDataTimestamp - cachedJobsLastUpdate > self._cacheExpirationPeriod) {
|
||||||
}).fail(function (data) {
|
var url = `${viewUrl}${self._jobsRequest}`;
|
||||||
GUI.log(i18n.getMessage('releaseCheckFailed', [self._jobName, 'failed to load builds']));
|
|
||||||
|
|
||||||
self._builds = cachedBuildsData;
|
$.get(url, jobsInfo => {
|
||||||
self._parseBuilds(callback);
|
GUI.log(i18n.getMessage('buildServerLoaded', ['jobs']));
|
||||||
});
|
|
||||||
|
// remove Betaflight prefix, rename Betaflight job to Development
|
||||||
|
var jobs = jobsInfo.jobs.map(job => {
|
||||||
|
return { title: job.name.replace('Betaflight ', '').replace('Betaflight', 'Development'), name: job.name };
|
||||||
|
})
|
||||||
|
|
||||||
|
// cache loaded info
|
||||||
|
object = {}
|
||||||
|
object[jobsDataTag] = jobs;
|
||||||
|
object[cacheLastUpdateTag] = $.now();
|
||||||
|
chrome.storage.local.set(object);
|
||||||
|
|
||||||
|
wrappedCallback(jobs);
|
||||||
|
}).error(xhr => {
|
||||||
|
GUI.log(i18n.getMessage('buildServerLoadFailed', ['jobs', `HTTP ${xhr.status}`]));
|
||||||
|
}).fail(() => wrappedCallback([]));
|
||||||
} else {
|
} else {
|
||||||
if (cachedBuildsData) {
|
if (cachedJobsData) {
|
||||||
GUI.log(i18n.getMessage('releaseCheckCached', [self._jobName]));
|
GUI.log(i18n.getMessage('buildServerUsingCached', ['jobs']));
|
||||||
}
|
}
|
||||||
|
|
||||||
self._builds = cachedBuildsData;
|
wrappedCallback(cachedJobsData);
|
||||||
self._parseBuilds(callback);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
JenkinsLoader.prototype._parseBuilds = function (callback) {
|
JenkinsLoader.prototype.loadBuilds = function (jobName, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
var jobUrl = `${self._url}/job/${jobName}`;
|
||||||
|
var buildsDataTag = `${jobUrl}BuildsData`;
|
||||||
|
var cacheLastUpdateTag = `${jobUrl}BuildsLastUpdate`
|
||||||
|
|
||||||
|
chrome.storage.local.get([cacheLastUpdateTag, buildsDataTag], function (result) {
|
||||||
|
var buildsDataTimestamp = $.now();
|
||||||
|
var cachedBuildsData = result[buildsDataTag];
|
||||||
|
var cachedBuildsLastUpdate = result[cacheLastUpdateTag];
|
||||||
|
|
||||||
|
if (!cachedBuildsData || !cachedBuildsLastUpdate || buildsDataTimestamp - cachedBuildsLastUpdate > self._cacheExpirationPeriod) {
|
||||||
|
var url = `${jobUrl}${self._buildsRequest}`;
|
||||||
|
|
||||||
|
$.get(url, function (buildsInfo) {
|
||||||
|
GUI.log(i18n.getMessage('buildServerLoaded', [jobName]));
|
||||||
|
|
||||||
|
// filter successful builds
|
||||||
|
var builds = buildsInfo.builds.filter(build => build.result == 'SUCCESS')
|
||||||
|
.map(build => ({
|
||||||
|
number: build.number,
|
||||||
|
artifacts: build.artifacts.map(artifact => artifact.relativePath),
|
||||||
|
changes: build.changeSet.items.map(item => '* ' + item.msg).join('<br>\n'),
|
||||||
|
timestamp: build.timestamp
|
||||||
|
}));
|
||||||
|
|
||||||
|
// cache loaded info
|
||||||
|
object = {}
|
||||||
|
object[buildsDataTag] = builds;
|
||||||
|
object[cacheLastUpdateTag] = $.now();
|
||||||
|
chrome.storage.local.set(object);
|
||||||
|
|
||||||
|
self._parseBuilds(jobUrl, jobName, builds, callback);
|
||||||
|
}).error(xhr => {
|
||||||
|
GUI.log(i18n.getMessage('buildServerLoadFailed', [jobName, `HTTP ${xhr.status}`]));
|
||||||
|
}).fail(() => {
|
||||||
|
self._parseBuilds(jobUrl, jobName, [], callback);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (cachedBuildsData) {
|
||||||
|
GUI.log(i18n.getMessage('buildServerUsingCached', [jobName]));
|
||||||
|
}
|
||||||
|
|
||||||
|
self._parseBuilds(jobUrl, jobName, cachedBuildsData, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
JenkinsLoader.prototype._parseBuilds = function (jobUrl, jobName, builds, callback) {
|
||||||
// convert from `build -> targets` to `target -> builds` mapping
|
// convert from `build -> targets` to `target -> builds` mapping
|
||||||
var targetBuilds = {};
|
var targetBuilds = {};
|
||||||
|
|
||||||
var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/;
|
var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/;
|
||||||
|
|
||||||
self._builds.forEach(build => {
|
builds.forEach(build => {
|
||||||
build.artifacts.forEach(relativePath => {
|
build.artifacts.forEach(relativePath => {
|
||||||
var match = targetFromFilenameExpression.exec(relativePath);
|
var match = targetFromFilenameExpression.exec(relativePath);
|
||||||
|
|
||||||
|
@ -70,15 +122,16 @@ JenkinsLoader.prototype._parseBuilds = function (callback) {
|
||||||
|
|
||||||
var version = match[1];
|
var version = match[1];
|
||||||
var target = match[2];
|
var target = match[2];
|
||||||
|
var date = new Date(build.timestamp);
|
||||||
|
|
||||||
var formattedDate = ("0" + build.date.getDate()).slice(-2) + "-" + ("0" + (build.date.getMonth()+1)).slice(-2) + "-" +
|
var formattedDate = ("0" + date.getDate()).slice(-2) + "-" + ("0" + (date.getMonth()+1)).slice(-2) + "-" +
|
||||||
build.date.getFullYear() + " " + ("0" + build.date.getHours()).slice(-2) + ":" + ("0" + build.date.getMinutes()).slice(-2);
|
date.getFullYear() + " " + ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2);
|
||||||
|
|
||||||
var descriptor = {
|
var descriptor = {
|
||||||
'releaseUrl': self._jobUrl + '/' + build.number,
|
'releaseUrl': jobUrl + '/' + build.number,
|
||||||
'name' : self._jobName + ' #' + build.number,
|
'name' : jobName + ' #' + build.number,
|
||||||
'version' : version + ' #' + build.number,
|
'version' : version + ' #' + build.number,
|
||||||
'url' : self._jobUrl + '/' + build.number + '/artifact/' + relativePath,
|
'url' : jobUrl + '/' + build.number + '/artifact/' + relativePath,
|
||||||
'file' : relativePath.split('/').slice(-1)[0],
|
'file' : relativePath.split('/').slice(-1)[0],
|
||||||
'target' : target,
|
'target' : target,
|
||||||
'date' : formattedDate,
|
'date' : formattedDate,
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
TABS.firmware_flasher = {
|
TABS.firmware_flasher = {
|
||||||
releases: null,
|
releases: null,
|
||||||
releaseChecker: new ReleaseChecker('firmware', 'https://api.github.com/repos/betaflight/betaflight/releases')
|
releaseChecker: new ReleaseChecker('firmware', 'https://api.github.com/repos/betaflight/betaflight/releases'),
|
||||||
|
jenkinsLoader: new JenkinsLoader('https://ci.betaflight.tech')
|
||||||
};
|
};
|
||||||
|
|
||||||
TABS.firmware_flasher.initialize = function (callback) {
|
TABS.firmware_flasher.initialize = function (callback) {
|
||||||
|
@ -28,7 +29,7 @@ TABS.firmware_flasher.initialize = function (callback) {
|
||||||
: "normal");
|
: "normal");
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#content').load("./tabs/firmware_flasher.html", function () {
|
function onDocumentLoad() {
|
||||||
FirmwareCache.load();
|
FirmwareCache.load();
|
||||||
FirmwareCache.onPutToCache(onFirmwareCacheUpdate);
|
FirmwareCache.onPutToCache(onFirmwareCacheUpdate);
|
||||||
FirmwareCache.onRemoveFromCache(onFirmwareCacheUpdate);
|
FirmwareCache.onRemoveFromCache(onFirmwareCacheUpdate);
|
||||||
|
@ -243,24 +244,21 @@ TABS.firmware_flasher.initialize = function (callback) {
|
||||||
{
|
{
|
||||||
tag: 'firmwareFlasherOptionLabelBuildTypeReleaseCandidate',
|
tag: 'firmwareFlasherOptionLabelBuildTypeReleaseCandidate',
|
||||||
loader: () => self.releaseChecker.loadReleaseData(releaseData => buildBoardOptions(releaseData, true))
|
loader: () => self.releaseChecker.loadReleaseData(releaseData => buildBoardOptions(releaseData, true))
|
||||||
},
|
|
||||||
{
|
|
||||||
tag: 'firmwareFlasherOptionLabelBuildTypeDevelopment',
|
|
||||||
loader: () => new JenkinsLoader('https://ci.betaflight.tech', 'Betaflight').loadBuilds(buildJenkinsBoardOptions)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tag: 'firmwareFlasherOptionLabelBuildTypeAKK3_3',
|
|
||||||
loader: () => new JenkinsLoader('https://ci.betaflight.tech', 'Betaflight Maintenance 3.3 (AKK - RDQ VTX Patch)').loadBuilds(buildJenkinsBoardOptions)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tag: 'firmwareFlasherOptionLabelBuildTypeAKK3_4',
|
|
||||||
loader: () => new JenkinsLoader('https://ci.betaflight.tech', 'Betaflight Maintenance 3.4 (AKK - RDQ VTX Patch)').loadBuilds(buildJenkinsBoardOptions)
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
var ciBuildsTypes = self.jenkinsLoader._jobs.map(job => {
|
||||||
|
return {
|
||||||
|
title: job.title,
|
||||||
|
loader: () => self.jenkinsLoader.loadBuilds(job.name, buildJenkinsBoardOptions)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
buildTypes = buildTypes.concat(ciBuildsTypes);
|
||||||
|
|
||||||
var buildType_e = $('select[name="build_type"]');
|
var buildType_e = $('select[name="build_type"]');
|
||||||
buildTypes.forEach((build, index) => {
|
buildTypes.forEach((build, index) => {
|
||||||
buildType_e.append($("<option value='{0}' selected>{1}</option>".format(index, i18n.getMessage(build.tag))))
|
buildType_e.append($("<option value='{0}' selected>{1}</option>".format(index, build.tag ? i18n.getMessage(build.tag) : build.title)))
|
||||||
});
|
});
|
||||||
|
|
||||||
showOrHideBuildTypeSelect();
|
showOrHideBuildTypeSelect();
|
||||||
|
@ -626,6 +624,10 @@ TABS.firmware_flasher.initialize = function (callback) {
|
||||||
});
|
});
|
||||||
|
|
||||||
GUI.content_ready(callback);
|
GUI.content_ready(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.jenkinsLoader.loadJobs('Firmware', () => {
|
||||||
|
$('#content').load("./tabs/firmware_flasher.html", onDocumentLoad);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue