Add flag to persist builds
Some checks failed
Some checks failed
This commit is contained in:
78
package-lock.json
generated
78
package-lock.json
generated
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"name": "archery",
|
||||
"version": "0.2.4",
|
||||
"version": "0.3.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "archery",
|
||||
"version": "0.2.4",
|
||||
"version": "0.3.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"body-parser": "^2.2.0",
|
||||
"body-parser": "^2.2.1",
|
||||
"ejs": "3.1.10",
|
||||
"express": "^5.1.0",
|
||||
"express-session": "1.18.2",
|
||||
"express-ws": "^5.0.2",
|
||||
"ky": "1.10.0",
|
||||
"ky": "1.14.0",
|
||||
"passport": "0.7.0",
|
||||
"passport-openidconnect": "0.1.2",
|
||||
"pg": "^8.16.3",
|
||||
@@ -23,9 +23,9 @@
|
||||
"sqids": "0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^5.0.3",
|
||||
"@types/express": "^5.0.5",
|
||||
"@types/express-session": "^1.18.2",
|
||||
"@types/express-ws": "3.0.5",
|
||||
"@types/express-ws": "3.0.6",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/passport": "1.0.17",
|
||||
"@types/passport-openidconnect": "0.1.3",
|
||||
@@ -376,15 +376,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz",
|
||||
"integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==",
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.5.tgz",
|
||||
"integrity": "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "^5.0.0",
|
||||
"@types/serve-static": "*"
|
||||
"@types/serve-static": "^1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express-serve-static-core": {
|
||||
@@ -411,9 +411,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express-ws": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-ws/-/express-ws-3.0.5.tgz",
|
||||
"integrity": "sha512-lbWMjoHrm/v85j81UCmb/GNZFO3genxRYBW1Ob7rjRI+zxUBR+4tcFuOpKKsYQ1LYTYiy3356epLeYi/5zxUwA==",
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-ws/-/express-ws-3.0.6.tgz",
|
||||
"integrity": "sha512-6ZDt+tMEQgM4RC1sMX1fIO7kHQkfUDlWfxoPddXUeeDjmc+Yt/fCzqXfp8rFahNr5eIxdomrWphLEWDkB2q3UQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -589,23 +589,27 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
|
||||
"integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz",
|
||||
"integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "^3.1.2",
|
||||
"content-type": "^1.0.5",
|
||||
"debug": "^4.4.0",
|
||||
"debug": "^4.4.3",
|
||||
"http-errors": "^2.0.0",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"iconv-lite": "^0.7.0",
|
||||
"on-finished": "^2.4.1",
|
||||
"qs": "^6.14.0",
|
||||
"raw-body": "^3.0.0",
|
||||
"type-is": "^2.0.0"
|
||||
"raw-body": "^3.0.1",
|
||||
"type-is": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
@@ -934,7 +938,6 @@
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
|
||||
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"accepts": "^2.0.0",
|
||||
"body-parser": "^2.2.0",
|
||||
@@ -1239,15 +1242,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
|
||||
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
@@ -1342,9 +1349,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ky": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/ky/-/ky-1.10.0.tgz",
|
||||
"integrity": "sha512-YRPCzHEWZffbfvmRrfwa+5nwBHwZuYiTrfDX0wuhGBPV0pA/zCqcOq93MDssON/baIkpYbvehIX5aLpMxrRhaA==",
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/ky/-/ky-1.14.0.tgz",
|
||||
"integrity": "sha512-Rczb6FMM6JT0lvrOlP5WUOCB7s9XKxzwgErzhKlKde1bEV90FXplV1o87fpt4PU/asJFiqjYJxAJyzJhcrxOsQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -1608,7 +1615,6 @@
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"pg-connection-string": "^2.9.1",
|
||||
"pg-pool": "^3.10.1",
|
||||
@@ -1819,22 +1825,6 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body/node_modules/iconv-lite": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
|
||||
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
|
||||
14
package.json
14
package.json
@@ -1,31 +1,31 @@
|
||||
{
|
||||
"name": "archery",
|
||||
"version": "0.2.4",
|
||||
"version": "0.3.0",
|
||||
"description": "Build Arch packages through a web interface",
|
||||
"keywords": [
|
||||
"docker",
|
||||
"arch",
|
||||
"artix"
|
||||
],
|
||||
"homepage": "https://github.com/CorySanin/archery#readme",
|
||||
"homepage": "https://git.sanin.dev/corysanin/archery#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/CorySanin/archery/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/CorySanin/archery.git"
|
||||
"url": "git+https://git.sanin.dev/corysanin/archery.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Cory Sanin",
|
||||
"type": "module",
|
||||
"main": "index.ts",
|
||||
"dependencies": {
|
||||
"body-parser": "^2.2.0",
|
||||
"body-parser": "^2.2.1",
|
||||
"ejs": "3.1.10",
|
||||
"express": "^5.1.0",
|
||||
"express-session": "1.18.2",
|
||||
"express-ws": "^5.0.2",
|
||||
"ky": "1.10.0",
|
||||
"ky": "1.14.0",
|
||||
"passport": "0.7.0",
|
||||
"passport-openidconnect": "0.1.2",
|
||||
"pg": "^8.16.3",
|
||||
@@ -34,9 +34,9 @@
|
||||
"sqids": "0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^5.0.3",
|
||||
"@types/express": "^5.0.5",
|
||||
"@types/express-session": "^1.18.2",
|
||||
"@types/express-ws": "3.0.5",
|
||||
"@types/express-ws": "3.0.6",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/passport": "1.0.17",
|
||||
"@types/passport-openidconnect": "0.1.3",
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
for (let btn of document.getElementsByClassName('copybtn')) {
|
||||
btn.addEventListener('click', e => {
|
||||
navigator.clipboard.writeText(e.target.previousElementSibling.innerText);
|
||||
});
|
||||
}
|
||||
});
|
||||
23
scripts/form.js
Normal file
23
scripts/form.js
Normal file
@@ -0,0 +1,23 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
for (let btn of document.getElementsByClassName('copybtn')) {
|
||||
btn.addEventListener('click', e => {
|
||||
navigator.clipboard.writeText(e.target.previousElementSibling.innerText);
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('persistChk')?.addEventListener('change', async e => {
|
||||
const sqid = document.getElementById('sqid').textContent;
|
||||
const persist = !!e.target?.checked;
|
||||
const resp = await fetch(`/build/${sqid}/persist`, {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ persist })
|
||||
});
|
||||
if (!resp.ok) {
|
||||
this.location.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
18
src/DB.ts
18
src/DB.ts
@@ -30,6 +30,7 @@ interface Build {
|
||||
pid?: number;
|
||||
sqid?: string;
|
||||
uuid: string;
|
||||
persist: boolean;
|
||||
}
|
||||
|
||||
interface User {
|
||||
@@ -128,6 +129,10 @@ class DB extends Store {
|
||||
uuid: {
|
||||
type: DataTypes.STRING,
|
||||
unique: true
|
||||
},
|
||||
persist: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false
|
||||
}
|
||||
});
|
||||
|
||||
@@ -262,6 +267,16 @@ class DB extends Store {
|
||||
});
|
||||
}
|
||||
|
||||
public async persist(id: number, persist: boolean = true): Promise<void> {
|
||||
await this.build.update({
|
||||
persist
|
||||
}, {
|
||||
where: {
|
||||
id
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async appendLog(buildId: number, type: LogType, chunk: string): Promise<void> {
|
||||
await this.logChunk.create({
|
||||
buildId,
|
||||
@@ -366,7 +381,8 @@ class DB extends Store {
|
||||
public async cleanup(): Promise<void> {
|
||||
await this.build.destroy({
|
||||
where: {
|
||||
startTime: { [Op.lt]: new Date(Date.now() - MONTH * 6) }
|
||||
startTime: { [Op.lt]: new Date(Date.now() - MONTH * 6) },
|
||||
persist: { [Op.eq]: false }
|
||||
},
|
||||
force: true
|
||||
});
|
||||
|
||||
11
src/Web.ts
11
src/Web.ts
@@ -297,6 +297,17 @@ class Web {
|
||||
res.redirect(`/build/${req.params.id}/`);
|
||||
});
|
||||
|
||||
app.post('/build/:id/persist', async (req, res) => {
|
||||
const build = await this.db.getBuild(sqids.decode(req.params.id)?.[0]);
|
||||
const persist = !! req?.body?.persist;
|
||||
if (!build) {
|
||||
res.sendStatus(404);
|
||||
return;
|
||||
}
|
||||
await this.db.persist(build.id, persist);
|
||||
res.sendStatus(200);
|
||||
})
|
||||
|
||||
this._webserver = this.app.listen(this.port, () => console.log(`archery is running on port ${this.port}`));
|
||||
}
|
||||
|
||||
|
||||
@@ -268,6 +268,10 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
.display-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#followCheckmarkContainer {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
<div class="content">
|
||||
<h1>Build #<%= build.id %></h1>
|
||||
<h2 id="buildStatus"><%= build.status %></h2>
|
||||
<% if (!public) { %>
|
||||
<h3 id="sqid" class="display-none"><%= build.sqid %></h3>
|
||||
<% } %>
|
||||
<div class="overflow-x">
|
||||
<div class="grid-2col">
|
||||
<label>Repo</label> <span><span><%= build.repo %></span> <button class="copybtn">Copy</button></span>
|
||||
@@ -21,6 +24,9 @@
|
||||
<% if (build.userId && build.userId !== '-1') { %>
|
||||
<label>Triggered by</label> <span><%= build.user.displayName %> (<%= build.user.username %>)</span>
|
||||
<% } %>
|
||||
<% if (!public) { %>
|
||||
<label>Persist</label> <span><input id="persistChk" type="checkbox" <% if (build.persist) { %>checked<% } %>/></span>
|
||||
<% } %>
|
||||
<% if (locals.shareable) { %>
|
||||
<label>Shareable link</label> <span><a href="<%= shareable %>"><%= shareable %></a> <button class="copybtn">Copy</button></span>
|
||||
<% } %>
|
||||
@@ -47,7 +53,7 @@
|
||||
</div>
|
||||
<%- include("footer", locals) %>
|
||||
<script src="/assets/js/timezone.js?v1" nonce="<%= cspNonce %>"></script>
|
||||
<script src="/assets/js/copy.js?v1" nonce="<%= cspNonce %>"></script>
|
||||
<script src="/assets/js/form.js?v1" nonce="<%= cspNonce %>"></script>
|
||||
<% if (!ended) { %>
|
||||
<script src="/assets/js/build.js?v3" nonce="<%= cspNonce %>"></script>
|
||||
<% } %>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<link rel="canonical" href="<%= page.canonical%>"/>
|
||||
<% } %>
|
||||
<link rel="shortcut icon" href="/assets/svg/favicon.svg">
|
||||
<link rel="stylesheet" href="/assets/css/styles.css?v4">
|
||||
<link rel="stylesheet" href="/assets/css/styles.css?v5">
|
||||
<script nonce="<%= cspNonce %>">
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.body.classList.remove('preload');
|
||||
|
||||
Reference in New Issue
Block a user