Skip to content

Commit 502a729

Browse files
committed
Merge branch 'master.global.env'
2 parents 6d344c3 + 833d0cb commit 502a729

File tree

10 files changed

+195
-27
lines changed

10 files changed

+195
-27
lines changed

backend/agent-socket-handlers/docker-socket-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class DockerSocketHandler extends AgentSocketHandler {
4949
await stack.delete(socket);
5050
}
5151

52-
let exitCode = await Terminal.exec(server, socket, terminalName, "git", ["clone", "-b", branch, gitUrl, stackName], server.stacksDir);
52+
let exitCode = await Terminal.exec(server, socket, terminalName, "git", [ "clone", "-b", branch, gitUrl, stackName ], server.stacksDir);
5353
if (exitCode !== 0) {
5454
throw new Error(`Failed to clone git repo [Exit Code ${exitCode}]`);
5555
}

backend/socket-handlers/main-socket-handler.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {
1818
import { passwordStrength } from "check-password-strength";
1919
import jwt from "jsonwebtoken";
2020
import { Settings } from "../settings";
21+
import fs, { promises as fsAsync } from "fs";
22+
import path from "path";
2123

2224
export class MainSocketHandler extends SocketHandler {
2325
create(socket: DockgeSocket, server: DockgeServer) {
@@ -242,6 +244,12 @@ export class MainSocketHandler extends SocketHandler {
242244
checkLogin(socket);
243245
const data = await Settings.getSettings("general");
244246

247+
if (fs.existsSync(path.join(server.stacksDir, "global.env"))) {
248+
data.globalENV = fs.readFileSync(path.join(server.stacksDir, "global.env"), "utf-8");
249+
} else {
250+
data.globalENV = "# VARIABLE=value #comment";
251+
}
252+
245253
callback({
246254
ok: true,
247255
data: data,
@@ -270,6 +278,16 @@ export class MainSocketHandler extends SocketHandler {
270278
if (!currentDisabledAuth && data.disableAuth) {
271279
await doubleCheckPassword(socket, currentPassword);
272280
}
281+
// Handle global.env
282+
if (data.globalENV && data.globalENV != "# VARIABLE=value #comment") {
283+
await fsAsync.writeFile(path.join(server.stacksDir, "global.env"), data.globalENV);
284+
} else {
285+
await fsAsync.rm(path.join(server.stacksDir, "global.env"), {
286+
recursive: true,
287+
force: true
288+
});
289+
}
290+
delete data.globalENV;
273291

274292
await Settings.setSettings("general", data);
275293

backend/stack.ts

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export class Stack {
101101
* Get the status of the stack from `docker compose ps --format json`
102102
*/
103103
async ps(): Promise<object> {
104-
let res = await childProcessAsync.spawn("docker", [ "compose", "ps", "--format", "json" ], {
104+
let res = await childProcessAsync.spawn("docker", this.getComposeOptions("ps", "--format", "json"), {
105105
cwd: this.path,
106106
encoding: "utf-8",
107107
});
@@ -117,7 +117,7 @@ export class Stack {
117117

118118
get isGitRepo(): boolean {
119119
try {
120-
execSync("git rev-parse --is-inside-work-tree", {cwd: this.path});
120+
execSync("git rev-parse --is-inside-work-tree", { cwd: this.path });
121121
return true;
122122
} catch (error) {
123123
return false;
@@ -127,7 +127,7 @@ export class Stack {
127127
get gitUrl(): string {
128128
if (this.isGitRepo) {
129129
try {
130-
let stdout = execSync("git config --get remote.origin.url", {cwd: this.path});
130+
let stdout = execSync("git config --get remote.origin.url", { cwd: this.path });
131131
return stdout.toString().trim();
132132
} catch (error) {
133133
return "";
@@ -139,7 +139,7 @@ export class Stack {
139139
get branch(): string {
140140
if (this.isGitRepo) {
141141
try {
142-
let stdout = execSync("git branch --show-current", {cwd: this.path});
142+
let stdout = execSync("git branch --show-current", { cwd: this.path });
143143
return stdout.toString().trim();
144144
} catch (error) {
145145
return "";
@@ -258,7 +258,7 @@ export class Stack {
258258

259259
async deploy(socket: DockgeSocket): Promise<number> {
260260
const terminalName = getComposeTerminalName(socket.endpoint, this.name);
261-
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "up", "-d", "--remove-orphans" ], this.path);
261+
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", this.getComposeOptions("up", "-d", "--remove-orphans"), this.path);
262262
if (exitCode !== 0) {
263263
throw new Error("Failed to deploy, please check the terminal output for more information.");
264264
}
@@ -267,7 +267,7 @@ export class Stack {
267267

268268
async delete(socket: DockgeSocket): Promise<number> {
269269
const terminalName = getComposeTerminalName(socket.endpoint, this.name);
270-
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "down", "--remove-orphans" ], this.path);
270+
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", this.getComposeOptions("down", "--remove-orphans"), this.path);
271271
if (exitCode !== 0) {
272272
throw new Error("Failed to delete, please check the terminal output for more information.");
273273
}
@@ -481,9 +481,22 @@ export class Stack {
481481
return stack;
482482
}
483483

484+
getComposeOptions(command : string, ...extraOptions : string[]) {
485+
//--env-file ./../global.env --env-file .env
486+
let options = [ "compose", command, ...extraOptions ];
487+
if (fs.existsSync(path.join(this.server.stacksDir, "global.env"))) {
488+
if (fs.existsSync(path.join(this.path, ".env"))) {
489+
options.splice(1, 0, "--env-file", "./.env");
490+
}
491+
options.splice(1, 0, "--env-file", "../global.env");
492+
}
493+
console.log(options);
494+
return options;
495+
}
496+
484497
async start(socket: DockgeSocket) {
485498
const terminalName = getComposeTerminalName(socket.endpoint, this.name);
486-
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "up", "-d", "--remove-orphans" ], this.path);
499+
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", this.getComposeOptions("up", "-d", "--remove-orphans"), this.path);
487500
if (exitCode !== 0) {
488501
throw new Error("Failed to start, please check the terminal output for more information.");
489502
}
@@ -492,7 +505,7 @@ export class Stack {
492505

493506
async stop(socket: DockgeSocket): Promise<number> {
494507
const terminalName = getComposeTerminalName(socket.endpoint, this.name);
495-
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "stop" ], this.path);
508+
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", this.getComposeOptions("stop"), this.path);
496509
if (exitCode !== 0) {
497510
throw new Error("Failed to stop, please check the terminal output for more information.");
498511
}
@@ -501,7 +514,7 @@ export class Stack {
501514

502515
async restart(socket: DockgeSocket): Promise<number> {
503516
const terminalName = getComposeTerminalName(socket.endpoint, this.name);
504-
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "restart" ], this.path);
517+
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", this.getComposeOptions("restart"), this.path);
505518
if (exitCode !== 0) {
506519
throw new Error("Failed to restart, please check the terminal output for more information.");
507520
}
@@ -510,7 +523,7 @@ export class Stack {
510523

511524
async down(socket: DockgeSocket): Promise<number> {
512525
const terminalName = getComposeTerminalName(socket.endpoint, this.name);
513-
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "down" ], this.path);
526+
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", this.getComposeOptions("down"), this.path);
514527
if (exitCode !== 0) {
515528
throw new Error("Failed to down, please check the terminal output for more information.");
516529
}
@@ -522,13 +535,13 @@ export class Stack {
522535

523536
if (this.isGitRepo) {
524537
// TODO: error handling e.g. local changes
525-
let exitCode = await Terminal.exec(this.server, socket, terminalName, "git", [ "pull" ], this.path);
538+
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", this.getComposeOptions("pull"), this.path);
526539
if (exitCode !== 0) {
527540
throw new Error("Failed to update, please check the terminal output for more information.");
528541
}
529542
}
530543

531-
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "pull" ], this.path);
544+
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", this.getComposeOptions("pull"), this.path);
532545
if (exitCode !== 0) {
533546
throw new Error("Failed to pull, please check the terminal output for more information.");
534547
}
@@ -540,7 +553,7 @@ export class Stack {
540553
return exitCode;
541554
}
542555

543-
exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "up", "-d", "--remove-orphans" ], this.path);
556+
exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", this.getComposeOptions("up", "-d", "--remove-orphans"), this.path);
544557
if (exitCode !== 0) {
545558
throw new Error("Failed to restart, please check the terminal output for more information.");
546559
}
@@ -597,7 +610,7 @@ export class Stack {
597610

598611
async joinCombinedTerminal(socket: DockgeSocket) {
599612
const terminalName = getCombinedTerminalName(socket.endpoint, this.name);
600-
const terminal = Terminal.getOrCreateTerminal(this.server, terminalName, "docker", [ "compose", "logs", "-f", "--tail", "100" ], this.path);
613+
const terminal = Terminal.getOrCreateTerminal(this.server, terminalName, "docker", this.getComposeOptions("logs", "-f", "--tail", "100"), this.path);
601614
terminal.enableKeepAlive = true;
602615
terminal.rows = COMBINED_TERMINAL_ROWS;
603616
terminal.cols = COMBINED_TERMINAL_COLS;
@@ -618,7 +631,7 @@ export class Stack {
618631
let terminal = Terminal.getTerminal(terminalName);
619632

620633
if (!terminal) {
621-
terminal = new InteractiveTerminal(this.server, terminalName, "docker", [ "compose", "exec", serviceName, shell ], this.path);
634+
terminal = new InteractiveTerminal(this.server, terminalName, "docker", this.getComposeOptions("exec", serviceName, shell), this.path);
622635
terminal.rows = TERMINAL_ROWS;
623636
log.debug("joinContainerTerminal", "Terminal created");
624637
}
@@ -631,7 +644,7 @@ export class Stack {
631644
let statusList = new Map<string, Array<object>>();
632645

633646
try {
634-
let res = await childProcessAsync.spawn("docker", [ "compose", "ps", "--format", "json" ], {
647+
let res = await childProcessAsync.spawn("docker", this.getComposeOptions("ps", "--format", "json"), {
635648
cwd: this.path,
636649
encoding: "utf-8",
637650
});
@@ -642,12 +655,15 @@ export class Stack {
642655

643656
let lines = res.stdout?.toString().split("\n");
644657

645-
const addLine = (obj: { Service: string, State: string, Name: string, Health: string }) => {
658+
const addLine = (obj: { Service: string, State: string, Name: string, Health: string, Ports: string }) => {
646659
if (!statusList.has(obj.Service)) {
647660
statusList.set(obj.Service, []);
648661
}
649662
statusList.get(obj.Service)?.push({
650663
status: obj.Health || obj.State,
664+
ports: obj.Ports.split(/,\s*/).filter((s) => {
665+
return s.indexOf("->") >= 0;
666+
}),
651667
name: obj.Name
652668
});
653669
};

common/util-common.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ function copyYAMLCommentsItems(items: any, srcItems: any) {
321321
* - "8000-9000:80"
322322
* - "127.0.0.1:8001:8001"
323323
* - "127.0.0.1:5000-5010:5000-5010"
324+
* - "0.0.0.0:8080->8080/tcp"
324325
* - "6060:6060/udp"
325326
* @param input
326327
* @param hostname
@@ -330,9 +331,19 @@ export function parseDockerPort(input: string, hostname: string) {
330331
let display;
331332

332333
const parts = input.split("/");
333-
const part1 = parts[0];
334+
let part1 = parts[0];
334335
let protocol = parts[1] || "tcp";
335336

337+
// coming from docker ps, split host part
338+
const arrow = part1.indexOf("->");
339+
if (arrow >= 0) {
340+
part1 = part1.split("->")[0];
341+
const colon = part1.indexOf(":");
342+
if (colon >= 0) {
343+
part1 = part1.split(":")[1];
344+
}
345+
}
346+
336347
// Split the last ":"
337348
const lastColon = part1.lastIndexOf(":");
338349

frontend/components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ declare module 'vue' {
2323
DockerStat: typeof import('./src/components/DockerStat.vue')['default']
2424
General: typeof import('./src/components/settings/General.vue')['default']
2525
GitOps: typeof import('./src/components/settings/GitOps.vue')['default']
26+
GlobalEnv: typeof import('./src/components/settings/GlobalEnv.vue')['default']
2627
HiddenInput: typeof import('./src/components/HiddenInput.vue')['default']
2728
Login: typeof import('./src/components/Login.vue')['default']
2829
NetworkInput: typeof import('./src/components/NetworkInput.vue')['default']
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<template>
2+
<div>
3+
<div v-if="settingsLoaded" class="my-4">
4+
<form class="my-4" autocomplete="off" @submit.prevent="saveGeneral">
5+
<div class="shadow-box mb-3 editor-box edit-mode">
6+
<prism-editor
7+
ref="editor"
8+
v-model="settings.globalENV"
9+
class="env-editor"
10+
:highlight="highlighterENV"
11+
line-numbers
12+
></prism-editor>
13+
</div>
14+
15+
<div class="my-4">
16+
<!-- Save Button -->
17+
<div>
18+
<button class="btn btn-primary" type="submit">
19+
{{ $t("Save") }}
20+
</button>
21+
</div>
22+
</div>
23+
</form>
24+
</div>
25+
</div>
26+
</template>
27+
28+
<script>
29+
import { highlight, languages } from "prismjs/components/prism-core";
30+
import { PrismEditor } from "vue-prism-editor";
31+
32+
let prismjsSymbolDefinition = {
33+
"symbol": {
34+
pattern: /(?<!\$)\$(\{[^{}]*\}|\w+)/,
35+
}
36+
};
37+
38+
export default {
39+
components: {
40+
PrismEditor,
41+
},
42+
43+
data() {
44+
return {
45+
};
46+
},
47+
48+
computed: {
49+
settings() {
50+
return this.$parent.$parent.$parent.settings;
51+
},
52+
saveSettings() {
53+
return this.$parent.$parent.$parent.saveSettings;
54+
},
55+
settingsLoaded() {
56+
return this.$parent.$parent.$parent.settingsLoaded;
57+
}
58+
},
59+
60+
methods: {
61+
/** Save the settings */
62+
saveGeneral() {
63+
this.saveSettings();
64+
},
65+
66+
highlighterENV(code) {
67+
if (!languages.docker_env) {
68+
languages.docker_env = {
69+
"comment": {
70+
pattern: /(^#| #).*$/m,
71+
greedy: true
72+
},
73+
"keyword": {
74+
pattern: /^\w*(?=[:=])/m,
75+
greedy: true
76+
},
77+
"value": {
78+
pattern: /(?<=[:=]).*?((?= #)|$)/m,
79+
greedy: true,
80+
inside: {
81+
"string": [
82+
{
83+
pattern: /^ *'.*?(?<!\\)'/m,
84+
},
85+
{
86+
pattern: /^ *".*?(?<!\\)"|^.*$/m,
87+
inside: prismjsSymbolDefinition
88+
},
89+
],
90+
},
91+
},
92+
};
93+
}
94+
return highlight(code, languages.docker_env);
95+
},
96+
},
97+
};
98+
</script>
99+
100+
<style scoped lang="scss">
101+
102+
.editor-box {
103+
font-family: 'JetBrains Mono', monospace;
104+
font-size: 14px;
105+
&.edit-mode {
106+
background-color: #2c2f38 !important;
107+
}
108+
}
109+
</style>

frontend/src/lang/en.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,6 @@
145145
"copy": "Copy",
146146
"GitOps": "GitOps",
147147
"GitConfig": "Git Configuration",
148-
"gitSync": "Sync Repo"
149-
}
148+
"gitSync": "Sync Repo",
149+
"GlobalEnv": "Global .env"
150+
}

0 commit comments

Comments
 (0)