mirror of
https://github.com/ohwgiles/laminar.git
synced 2024-10-27 20:34:20 +00:00
resolves #61: clickable up/downstream triggers
Recognises triggers in build logs and converts them to hyperlinks. Also separates upstream job from reason string and allows both to be provided
This commit is contained in:
parent
f5e719ac02
commit
63301c73d9
@ -1,5 +1,5 @@
|
|||||||
///
|
///
|
||||||
/// Copyright 2015-2017 Oliver Giles
|
/// Copyright 2015-2018 Oliver Giles
|
||||||
///
|
///
|
||||||
/// This file is part of Laminar
|
/// This file is part of Laminar
|
||||||
///
|
///
|
||||||
@ -36,20 +36,13 @@ static int setParams(int argc, char** argv, T& request) {
|
|||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int argsConsumed = n;
|
|
||||||
|
|
||||||
char* job = getenv("JOB");
|
char* job = getenv("JOB");
|
||||||
char* num = getenv("RUN");
|
char* num = getenv("RUN");
|
||||||
char* reason = getenv("LAMINAR_REASON");
|
char* reason = getenv("LAMINAR_REASON");
|
||||||
|
|
||||||
if(job && num) n+=2;
|
auto params = request.initParams(n + (job&&num?2:0) + (reason?1:0));
|
||||||
else if(reason) n++;
|
|
||||||
|
|
||||||
if(n == 0) return argsConsumed;
|
for(int i = 0; i < n; ++i) {
|
||||||
|
|
||||||
auto params = request.initParams(n);
|
|
||||||
|
|
||||||
for(int i = 0; i < argsConsumed; ++i) {
|
|
||||||
char* name = argv[i];
|
char* name = argv[i];
|
||||||
char* val = strchr(name, '=');
|
char* val = strchr(name, '=');
|
||||||
*val++ = '\0';
|
*val++ = '\0';
|
||||||
@ -57,19 +50,28 @@ static int setParams(int argc, char** argv, T& request) {
|
|||||||
params[i].setValue(val);
|
params[i].setValue(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int argsConsumed = n;
|
||||||
|
|
||||||
if(job && num) {
|
if(job && num) {
|
||||||
params[argsConsumed].setName("=parentJob");
|
params[n].setName("=parentJob");
|
||||||
params[argsConsumed].setValue(job);
|
params[n++].setValue(job);
|
||||||
params[argsConsumed+1].setName("=parentBuild");
|
params[n].setName("=parentBuild");
|
||||||
params[argsConsumed+1].setValue(num);
|
params[n++].setValue(num);
|
||||||
} else if(reason) {
|
}
|
||||||
params[argsConsumed].setName("=reason");
|
if(reason) {
|
||||||
params[argsConsumed].setValue(reason);
|
params[n].setName("=reason");
|
||||||
|
params[n].setValue(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
return argsConsumed;
|
return argsConsumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void printTriggerLink(const char* job, uint run) {
|
||||||
|
// use a private ANSI CSI sequence to mark the JOB:NUM so the
|
||||||
|
// frontend can recognise it and generate a hyperlink.
|
||||||
|
printf("\033[{%s:%d\033\\\n", job, run);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
if(argc < 2) {
|
if(argc < 2) {
|
||||||
fprintf(stderr, "Usage: %s <command> [parameters...]\n", argv[0]);
|
fprintf(stderr, "Usage: %s <command> [parameters...]\n", argv[0]);
|
||||||
@ -129,7 +131,7 @@ int main(int argc, char** argv) {
|
|||||||
fprintf(stderr, "Failed to start job '%s'\n", argv[2]);
|
fprintf(stderr, "Failed to start job '%s'\n", argv[2]);
|
||||||
ret = ENOENT;
|
ret = ENOENT;
|
||||||
}
|
}
|
||||||
printf("%s:%d\n", argv[jobNameIndex], resp.getBuildNum());
|
printTriggerLink(argv[jobNameIndex], resp.getBuildNum());
|
||||||
}));
|
}));
|
||||||
jobNameIndex += n + 1;
|
jobNameIndex += n + 1;
|
||||||
} while(jobNameIndex < argc);
|
} while(jobNameIndex < argc);
|
||||||
@ -150,7 +152,7 @@ int main(int argc, char** argv) {
|
|||||||
req.setJobName(argv[jobNameIndex]);
|
req.setJobName(argv[jobNameIndex]);
|
||||||
int n = setParams(argc - jobNameIndex - 1, &argv[jobNameIndex + 1], req);
|
int n = setParams(argc - jobNameIndex - 1, &argv[jobNameIndex + 1], req);
|
||||||
ts.add(req.send().then([&ret,argv,jobNameIndex](capnp::Response<LaminarCi::RunResults> resp){
|
ts.add(req.send().then([&ret,argv,jobNameIndex](capnp::Response<LaminarCi::RunResults> resp){
|
||||||
printf("%s:%d\n", argv[jobNameIndex], resp.getBuildNum());
|
printTriggerLink(argv[jobNameIndex], resp.getBuildNum());
|
||||||
if(resp.getResult() != LaminarCi::JobResult::SUCCESS) {
|
if(resp.getResult() != LaminarCi::JobResult::SUCCESS) {
|
||||||
ret = EFAILED;
|
ret = EFAILED;
|
||||||
}
|
}
|
||||||
|
@ -178,20 +178,22 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
j.set("time", time(nullptr));
|
j.set("time", time(nullptr));
|
||||||
j.startObject("data");
|
j.startObject("data");
|
||||||
if(client->scope.type == MonitorScope::RUN) {
|
if(client->scope.type == MonitorScope::RUN) {
|
||||||
db->stmt("SELECT queuedAt,startedAt,completedAt, result, reason FROM builds WHERE name = ? AND number = ?")
|
db->stmt("SELECT queuedAt,startedAt,completedAt,result,reason,parentJob,parentBuild FROM builds WHERE name = ? AND number = ?")
|
||||||
.bind(client->scope.job, client->scope.num)
|
.bind(client->scope.job, client->scope.num)
|
||||||
.fetch<time_t, time_t, time_t, int, std::string>([&](time_t queued, time_t started, time_t completed, int result, std::string reason) {
|
.fetch<time_t, time_t, time_t, int, std::string, std::string, uint>([&](time_t queued, time_t started, time_t completed, int result, std::string reason, std::string parentJob, uint parentBuild) {
|
||||||
j.set("queued", started-queued);
|
j.set("queued", started-queued);
|
||||||
j.set("started", started);
|
j.set("started", started);
|
||||||
j.set("completed", completed);
|
j.set("completed", completed);
|
||||||
j.set("result", to_string(RunState(result)));
|
j.set("result", to_string(RunState(result)));
|
||||||
j.set("reason", reason);
|
j.set("reason", reason);
|
||||||
|
j.startObject("upstream").set("name", parentJob).set("num", parentBuild).EndObject(2);
|
||||||
});
|
});
|
||||||
if(const Run* run = activeRun(client->scope.job, client->scope.num)) {
|
if(const Run* run = activeRun(client->scope.job, client->scope.num)) {
|
||||||
j.set("queued", run->startedAt - run->queuedAt);
|
j.set("queued", run->startedAt - run->queuedAt);
|
||||||
j.set("started", run->startedAt);
|
j.set("started", run->startedAt);
|
||||||
j.set("reason", run->reason());
|
|
||||||
j.set("result", to_string(RunState::RUNNING));
|
j.set("result", to_string(RunState::RUNNING));
|
||||||
|
j.set("reason", run->reason());
|
||||||
|
j.startObject("upstream").set("name", run->parentName).set("num", run->parentBuild).EndObject(2);
|
||||||
db->stmt("SELECT completedAt - startedAt FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 1")
|
db->stmt("SELECT completedAt - startedAt FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 1")
|
||||||
.bind(run->name)
|
.bind(run->name)
|
||||||
.fetch<uint>([&](uint lastRuntime){
|
.fetch<uint>([&](uint lastRuntime){
|
||||||
|
@ -294,6 +294,7 @@
|
|||||||
<div style="clear:both;"></div>
|
<div style="clear:both;"></div>
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>Reason</dt><dd>{{job.reason}}</dd>
|
<dt>Reason</dt><dd>{{job.reason}}</dd>
|
||||||
|
<dt v-show="job.upstream.num > 0">Upstream</dt><dd v-show="job.upstream.num > 0"><router-link :to="'/jobs/'+job.upstream.name">{{job.upstream.name}}</router-link> <router-link :to="'/jobs/'+job.upstream.name+'/'+job.upstream.num">#{{job.upstream.num}}</router-link></li></dd>
|
||||||
<dt>Queued for</dt><dd>{{job.queued}}s</dd>
|
<dt>Queued for</dt><dd>{{job.queued}}s</dd>
|
||||||
<dt>Started</dt><dd>{{formatDate(job.started)}}</dd>
|
<dt>Started</dt><dd>{{formatDate(job.started)}}</dd>
|
||||||
<dt v-show="runComplete(job)">Completed</dt><dd v-show="job.completed">{{formatDate(job.completed)}}</dd>
|
<dt v-show="runComplete(job)">Completed</dt><dd v-show="job.completed">{{formatDate(job.completed)}}</dd>
|
||||||
|
@ -655,14 +655,14 @@ var Job = function() {
|
|||||||
|
|
||||||
const Run = function() {
|
const Run = function() {
|
||||||
var state = {
|
var state = {
|
||||||
job: { artifacts: [] },
|
job: { artifacts: [], upstream: {} },
|
||||||
latestNum: null,
|
latestNum: null,
|
||||||
log: '',
|
log: '',
|
||||||
autoscroll: false
|
autoscroll: false
|
||||||
};
|
};
|
||||||
var firstLog = false;
|
var firstLog = false;
|
||||||
var logHandler = function(vm, d) {
|
var logHandler = function(vm, d) {
|
||||||
state.log += ansi_up.ansi_to_html(d.replace(/</g,'<').replace(/>/g,'>'));
|
state.log += ansi_up.ansi_to_html(d.replace(/</g,'<').replace(/>/g,'>').replace(/\033\[\{([^:]+):(\d+)\033\\/g, (m,$1,$2)=>{return '<a href="/jobs/'+$1+'" onclick="return vroute(this);">'+$1+'</a>:<a href="/jobs/'+$1+'/'+$2+'" onclick="return vroute(this);">#'+$2+'</a>';}));
|
||||||
vm.$forceUpdate();
|
vm.$forceUpdate();
|
||||||
if (!firstLog) {
|
if (!firstLog) {
|
||||||
firstLog = true;
|
firstLog = true;
|
||||||
|
@ -159,9 +159,6 @@ bool Run::configure(uint buildNum, std::shared_ptr<Node> nd, const kj::Directory
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string Run::reason() const {
|
std::string Run::reason() const {
|
||||||
if(!parentName.empty()) {
|
|
||||||
return std::string("Triggered by upstream ") + parentName + " #" + std::to_string(parentBuild);
|
|
||||||
}
|
|
||||||
return reasonMsg;
|
return reasonMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user