diff --git a/src/client.cpp b/src/client.cpp index 4ba28b4..d72ecec 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1,5 +1,5 @@ /// -/// Copyright 2015-2017 Oliver Giles +/// Copyright 2015-2018 Oliver Giles /// /// This file is part of Laminar /// @@ -36,20 +36,13 @@ static int setParams(int argc, char** argv, T& request) { n++; } - int argsConsumed = n; - char* job = getenv("JOB"); char* num = getenv("RUN"); char* reason = getenv("LAMINAR_REASON"); - if(job && num) n+=2; - else if(reason) n++; - - if(n == 0) return argsConsumed; + auto params = request.initParams(n + (job&&num?2:0) + (reason?1:0)); - auto params = request.initParams(n); - - for(int i = 0; i < argsConsumed; ++i) { + for(int i = 0; i < n; ++i) { char* name = argv[i]; char* val = strchr(name, '='); *val++ = '\0'; @@ -57,19 +50,28 @@ static int setParams(int argc, char** argv, T& request) { params[i].setValue(val); } + int argsConsumed = n; + if(job && num) { - params[argsConsumed].setName("=parentJob"); - params[argsConsumed].setValue(job); - params[argsConsumed+1].setName("=parentBuild"); - params[argsConsumed+1].setValue(num); - } else if(reason) { - params[argsConsumed].setName("=reason"); - params[argsConsumed].setValue(reason); + params[n].setName("=parentJob"); + params[n++].setValue(job); + params[n].setName("=parentBuild"); + params[n++].setValue(num); + } + if(reason) { + params[n].setName("=reason"); + params[n].setValue(reason); } 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) { if(argc < 2) { fprintf(stderr, "Usage: %s [parameters...]\n", argv[0]); @@ -129,7 +131,7 @@ int main(int argc, char** argv) { fprintf(stderr, "Failed to start job '%s'\n", argv[2]); ret = ENOENT; } - printf("%s:%d\n", argv[jobNameIndex], resp.getBuildNum()); + printTriggerLink(argv[jobNameIndex], resp.getBuildNum()); })); jobNameIndex += n + 1; } while(jobNameIndex < argc); @@ -150,7 +152,7 @@ int main(int argc, char** argv) { req.setJobName(argv[jobNameIndex]); int n = setParams(argc - jobNameIndex - 1, &argv[jobNameIndex + 1], req); ts.add(req.send().then([&ret,argv,jobNameIndex](capnp::Response resp){ - printf("%s:%d\n", argv[jobNameIndex], resp.getBuildNum()); + printTriggerLink(argv[jobNameIndex], resp.getBuildNum()); if(resp.getResult() != LaminarCi::JobResult::SUCCESS) { ret = EFAILED; } diff --git a/src/laminar.cpp b/src/laminar.cpp index 4007904..941b270 100644 --- a/src/laminar.cpp +++ b/src/laminar.cpp @@ -178,20 +178,22 @@ void Laminar::sendStatus(LaminarClient* client) { j.set("time", time(nullptr)); j.startObject("data"); 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) - .fetch([&](time_t queued, time_t started, time_t completed, int result, std::string reason) { + .fetch([&](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("started", started); j.set("completed", completed); j.set("result", to_string(RunState(result))); 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)) { j.set("queued", run->startedAt - run->queuedAt); j.set("started", run->startedAt); - j.set("reason", run->reason()); 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") .bind(run->name) .fetch([&](uint lastRuntime){ diff --git a/src/resources/index.html b/src/resources/index.html index f24a0ac..8b211fd 100644 --- a/src/resources/index.html +++ b/src/resources/index.html @@ -294,6 +294,7 @@
Reason
{{job.reason}}
+
Upstream
{{job.upstream.name}} #{{job.upstream.num}}
Queued for
{{job.queued}}s
Started
{{formatDate(job.started)}}
Completed
{{formatDate(job.completed)}}
diff --git a/src/resources/js/app.js b/src/resources/js/app.js index 18437e2..09ca0d2 100644 --- a/src/resources/js/app.js +++ b/src/resources/js/app.js @@ -655,14 +655,14 @@ var Job = function() { const Run = function() { var state = { - job: { artifacts: [] }, + job: { artifacts: [], upstream: {} }, latestNum: null, log: '', autoscroll: false }; var firstLog = false; var logHandler = function(vm, d) { - state.log += ansi_up.ansi_to_html(d.replace(//g,'>')); + state.log += ansi_up.ansi_to_html(d.replace(//g,'>').replace(/\033\[\{([^:]+):(\d+)\033\\/g, (m,$1,$2)=>{return ''+$1+':#'+$2+'';})); vm.$forceUpdate(); if (!firstLog) { firstLog = true; diff --git a/src/run.cpp b/src/run.cpp index d1ad469..ba818a3 100644 --- a/src/run.cpp +++ b/src/run.cpp @@ -159,9 +159,6 @@ bool Run::configure(uint buildNum, std::shared_ptr nd, const kj::Directory } std::string Run::reason() const { - if(!parentName.empty()) { - return std::string("Triggered by upstream ") + parentName + " #" + std::to_string(parentBuild); - } return reasonMsg; }