Add cancel button
This commit is contained in:
parent
40f04162d0
commit
413a756951
@ -7,6 +7,11 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const elements = document.getElementsByClassName('to-local-time');
|
||||
for (let element of elements) {
|
||||
const innerText = element.innerText;
|
||||
if (element.firstChild) {
|
||||
element.replaceChild(document.createTextNode(window.formatTime(innerText)), element.firstChild);
|
||||
}
|
||||
else {
|
||||
element.appendChild(document.createTextNode('-'));
|
||||
}
|
||||
}
|
||||
});
|
@ -15,11 +15,15 @@ interface BuildEvent {
|
||||
message: any;
|
||||
}
|
||||
|
||||
function getContainerName(id: number) {
|
||||
return `archery-build-${id}`;
|
||||
}
|
||||
|
||||
class BuildController extends EventEmitter {
|
||||
private db: DB;
|
||||
private process: spawn.ChildProcess | null = null;
|
||||
private running: boolean = false;
|
||||
private interval: NodeJS.Timeout;
|
||||
private cancelled: boolean = false;
|
||||
|
||||
constructor(config = {}) {
|
||||
super();
|
||||
@ -37,6 +41,7 @@ class BuildController extends EventEmitter {
|
||||
|
||||
private kickOffBuild = async () => {
|
||||
this.running = true;
|
||||
this.cancelled = false;
|
||||
const build = await this.db.dequeue();
|
||||
if (build === null) {
|
||||
this.running = false;
|
||||
@ -80,7 +85,7 @@ class BuildController extends EventEmitter {
|
||||
|
||||
private build = async (build: Build) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const docker = this.process = spawn.spawn('docker', this.createBuildParams(build));
|
||||
const docker = spawn.spawn('docker', this.createBuildParams(build));
|
||||
docker.on('spawn', () => {
|
||||
const remainder = {
|
||||
std: '',
|
||||
@ -106,8 +111,7 @@ class BuildController extends EventEmitter {
|
||||
docker.stderr.on('data', createLogFunction('err'));
|
||||
});
|
||||
docker.on('close', (code) => {
|
||||
this.process = null;
|
||||
const status = code === 0 ? 'success' : 'error';
|
||||
const status = code === 0 ? 'success' : (this.cancelled ? 'cancelled' : 'error');
|
||||
this.emitLog({
|
||||
id: build.id,
|
||||
type: 'finish',
|
||||
@ -115,12 +119,7 @@ class BuildController extends EventEmitter {
|
||||
});
|
||||
this.db.finishBuild(build.id, status);
|
||||
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
reject(code);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -136,15 +135,40 @@ class BuildController extends EventEmitter {
|
||||
// TODO: implement COMMIT
|
||||
params.push('-e', `COMMIT=${build.commit}`);
|
||||
}
|
||||
params.push('--name', getContainerName(build.id));
|
||||
params.push(docker_images[build.distro]);
|
||||
return params;
|
||||
}
|
||||
|
||||
cancelBuild = async (pid: number) => {
|
||||
const p = this.process
|
||||
if (p && p.pid === pid) {
|
||||
return p.kill();
|
||||
cancelBuild = async (id: number) => {
|
||||
const running = this.running;
|
||||
const build = await this.db.getBuild(id);
|
||||
if (running && build.status === 'queued') {
|
||||
await this.db.finishBuild(id, 'cancelled');
|
||||
return;
|
||||
}
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const dockerPs = spawn.spawn('docker', ['ps', '--filter', `name=${getContainerName(id)}`, '--format', '{{.ID}}']);
|
||||
let output = '';
|
||||
dockerPs.on('spawn', () => {
|
||||
dockerPs.stdout.on('data', (data: Buffer | string) => {
|
||||
output += data.toString();
|
||||
});
|
||||
});
|
||||
dockerPs.on('close', (code) => {
|
||||
if (code > 0) {
|
||||
return reject('failed to get container id');
|
||||
}
|
||||
this.cancelled = true;
|
||||
const dockerKill = spawn.spawn('docker', ['stop', output.trim()]);
|
||||
dockerKill.on('close', (code) => {
|
||||
if (code > 0) {
|
||||
return reject('failed to kill container');
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setDB = (db: DB) => {
|
||||
|
21
src/Web.ts
21
src/Web.ts
@ -33,12 +33,12 @@ class Web {
|
||||
private _webserver: http.Server | null = null;
|
||||
private db: DB;
|
||||
private buildController: BuildController;
|
||||
private app: Express;
|
||||
private app: expressWs.Application;
|
||||
private port: number;
|
||||
|
||||
constructor(options: WebConfig = {}) {
|
||||
const app: Express = this.app = express();
|
||||
const wsApp = expressWs(app).app;
|
||||
const app: Express = express();
|
||||
const wsApp = this.app = expressWs(app).app;
|
||||
this.port = notStupidParseInt(process.env.PORT) || options['port'] as number || 8080;
|
||||
|
||||
app.set('trust proxy', 1);
|
||||
@ -120,6 +120,21 @@ class Web {
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/build/:num/cancel', async (req, res) => {
|
||||
const build = await this.db.getBuild(parseInt(req.params.num));
|
||||
if (!build) {
|
||||
res.sendStatus(404);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.buildController.cancelBuild(build.id);
|
||||
}
|
||||
catch (ex) {
|
||||
console.error(ex);
|
||||
}
|
||||
res.redirect(`/build/${build.id}`);
|
||||
});
|
||||
|
||||
app.get('/build/:num/logs/?', async (req, res) => {
|
||||
const build = await this.db.getBuild(parseInt(req.params.num));
|
||||
if (!build) {
|
||||
|
@ -99,6 +99,7 @@ form {
|
||||
button,
|
||||
a.button,
|
||||
input[type="submit"] {
|
||||
font-size: 12pt;
|
||||
background-color: var(--primary);
|
||||
border: .4em double var(--primary);
|
||||
border-radius: .6em;
|
||||
@ -106,7 +107,7 @@ input[type="submit"] {
|
||||
padding: .3em .6em;
|
||||
color: #fff;
|
||||
margin-bottom: .4em;
|
||||
|
||||
text-decoration: none;
|
||||
box-shadow: 0px .4em 0 0 var(--primary-dark);
|
||||
|
||||
&:active {
|
||||
|
@ -18,6 +18,11 @@
|
||||
<label>Dependencies</label> <span><%= build.dependencies %></span>
|
||||
<label>Start time</label> <span class="to-local-time"><%= build.startTime %></span>
|
||||
</div>
|
||||
<% if (!ended) { %>
|
||||
<div>
|
||||
<a href="/build/<%= build.id %>/cancel" class="button">Cancel build</a>
|
||||
</div>
|
||||
<% } %>
|
||||
<p><a href="/build/<%= build.id %>/logs">Full logs</a></p>
|
||||
<div class="logs" id="logs">
|
||||
<% (log || []).forEach(line => { %>
|
||||
|
Loading…
x
Reference in New Issue
Block a user