refactor(Apps/Dashboard): Remove Deno as a dependency to the dashboard (#16934)

* remove deno as a dependency

* use the ACORE_VERSION env var

* I forgot client-data

* accidentally removed too much

* docker-cmd: extraneous parallel flag

* typo

* remove docker image prune -af

the `docker image prune` removes the containers we just build.

* fetch everything in the beginning
This commit is contained in:
Mike Delago
2023-09-09 19:12:47 -04:00
committed by GitHub
parent f6d11d526b
commit c43e1b8c0c
10 changed files with 206 additions and 431 deletions

184
apps/docker/docker-cmd.sh Normal file
View File

@@ -0,0 +1,184 @@
#!/bin/bash
# TODO(michaeldelago) decide if we need a wrapper like this around docker
# commands.
#
# Running the docker commands should be simple and familiar.
# Introducting extra steps through the dashboard can cause issues with people
# getting started, especially if they already know docker.
#
# If a new user knows docker, they will feel (pretty close) to right at home.
# If a new user doesn't know docker, it's easy to learn and the knowledge
# applies to much more than azerothcore
set -euo pipefail
COMPOSE_DOCKER_CLI_BUILD="1"
DOCKER_BUILDKIT="1"
# BUILDKIT_INLINE_CACHE="1"
function usage () {
cat <<EOF
Wrapper for shell scripts around docker
usage: $(basename $0) ACTION [ ACTION... ] [ ACTION_ARG... ]
actions:
EOF
# the `-s` will remove the "#" and properly space the action and description
cat <<EOF | column -t -l2 -s'#'
> start:app # Start the development worldserver and authserver
> start:app:d # Start the development worldserver and authserver in detached mode
> build # build the development worldserver and authserver
> pull # pull the development worldserver and authserver
> build:nocache # build the development worldserver and authserver without cache
> clean:build # clean build artifacts from the dev server
> client-data # download client data in the dev server
> dev:up start # the dev server
> dev:build # compile azerothcore using the dev server
> dev:dash # execute the dashboard in the dev server container
> dev:shell [ ARGS... ] # open a bash shell in the dev server
> prod:build # Build the service containers used by acore-docker
> prod:pull # Pull the containers used by acore-docker
> prod:up # Start the services used by acore-docker
> prod:up:d # start the services used by acore-docker in the background
> attach SERVICE # attach to a service currently running in docker compose
EOF
}
# If no args, just spit usage and exit
[[ $# -eq 0 ]] && usage && exit
# loop through commands passed
while [[ $# -gt 0 ]]; do
case "$1" in
start:app)
set -x
docker compose --profile app up
set +x
# pop the head off of the queue of args
# After this, the value of $1 is the value of $2
shift
;;
start:app:d)
set -x
docker compose --profile app up -d
set +x
shift
;;
build)
set -x
docker compose --profile local --profile dev --profile dev-build build
docker compose --profile dev-build run --rm --no-deps ac-dev-build /bin/bash /azerothcore/apps/docker/docker-build-dev.sh
set +x
shift
;;
pull)
set -x
docker compose --profile local --profile dev --profile dev-build pull
docker image prune -f
set +x
shift
;;
build:nocache)
set -x
docker compose --profile local --profile dev --profile dev-build build --no-cache
docker image prune -f
docker compose run --rm --no-deps ac-dev-build /bin/bash /azerothcore/apps/docker/docker-build-dev.sh
set +x
shift
;;
clean:build)
set -x
docker image prune -f
docker compose run --rm --no-deps ac-dev-server bash acore.sh compiler clean
docker compose run --rm --no-deps ac-dev-server bash acore.sh compiler ccacheClean
set +x
shift
;;
client-data)
set -x
docker compose run --rm --no-deps ac-dev-server bash acore.sh client-data
set +x
shift
;;
dev:up)
set -x
docker compose up -d ac-dev-server
set +x
shift
;;
dev:build)
set -x
docker compose run --rm ac-dev-server bash acore.sh compiler build
set +x
shift
;;
dev:dash)
set -x
docker compose run --rm ac-dev-server bash /azerothcore/acore.sh ${@:2}
set +x
shift
;;
dev:shell)
set -x
docker compose up -d ac-dev-server
docker compose exec ac-dev-server bash ${@:2}
set +x
shift
;;
build:prod|prod:build)
set -x
docker compose --profile build
docker image prune -f
set +x
shift
;;
pull:prod|prod:pull)
set -x
docker compose --profile prod pull
set +x
shift
;;
prod:up|start:prod)
set -x
docker compose --profile prod-app up
set +x
shift
;;
prod:up:d|start:prod:d)
set -x
docker compose --profile prod-app up -d
set +x
shift
;;
attach)
SERVICE="$2"
set -x
docker compose attach "$SERVICE"
set +x
shift
shift # Second to pass the argument
;;
*)
echo "Unknown or empty arg"
usage
exit 1
esac
done

View File

@@ -1,330 +0,0 @@
import { Command } from "https://cdn.deno.land/cmd/versions/v1.2.0/raw/mod.ts";
import * as ink from "https://deno.land/x/ink/mod.ts";
import {
Input,
Select,
} from "https://deno.land/x/cliffy@v0.25.2/prompt/mod.ts";
import * as semver from "https://deno.land/std@0.159.0/semver/mod.ts";
const program = new Command();
const env = {
COMPOSE_DOCKER_CLI_BUILD: "1",
DOCKER_BUILDKIT: "1",
// BUILDKIT_INLINE_CACHE: "1",
};
const MIN_COMPOSE_VERSION = "2.0.0";
program
.name("acore.sh docker")
.description("Shell scripts for docker")
.version("1.0.0");
shellCommandFactory(
"start:app",
"Startup the authserver and worldserver apps",
["docker compose --profile app up"],
env
);
shellCommandFactory(
"start:app:d",
"Startup the authserver and worldserver apps in detached mode",
["docker compose --profile app up -d"],
env
);
shellCommandFactory(
"build",
"Build the authserver and worldserver",
[
"docker compose --profile local --profile dev --profile dev-build build --parallel",
"docker image prune -f",
"docker compose run --rm --no-deps ac-dev-build bash apps/docker/docker-build-dev.sh",
],
env
);
shellCommandFactory(
"pull",
"Pull build and local images",
[
"docker compose --profile local --profile dev --profile dev-build pull --parallel",
"docker image prune -f",
],
env
);
shellCommandFactory(
"build:nocache",
"Build the authserver and worldserver without docker cache",
[
"docker compose --profile local --profile dev --profile dev-build build --no-cache --parallel",
"docker image prune -f",
"docker compose run --rm --no-deps ac-dev-build bash apps/docker/docker-build-dev.sh",
],
env
);
shellCommandFactory(
"clean:build",
"Clean build files",
[
"docker image prune -f",
`docker compose run --rm --no-deps ac-dev-server bash acore.sh compiler clean`,
`docker compose run --rm --no-deps ac-dev-server bash acore.sh compiler ccacheClean`,
],
env
);
shellCommandFactory(
"client-data",
"Download client data inside the ac-data volume",
["docker compose run --rm --no-deps ac-dev-server bash acore.sh client-data"],
env
);
shellCommandFactory(
"dev:up",
"Start the dev server container in background",
["docker compose up -d ac-dev-server"],
env
);
shellCommandFactory(
"dev:build",
"Build using the dev server",
["docker compose run --rm ac-dev-server bash acore.sh compiler build"],
env
);
shellCommandFactory(
"dev:dash [args...]",
"Execute acore dashboard within a running ac-dev-server",
["docker compose run --rm ac-dev-server bash acore.sh"],
env
);
shellCommandFactory(
"dev:shell [args...]",
"Open an interactive shell within the dev server",
[
"docker compose up -d ac-dev-server",
"docker compose exec ac-dev-server bash",
],
env
);
shellCommandFactory(
"prod:build",
"[TEST ONLY] Build producion services",
["docker compose --profile prod build --parallel", "docker image prune -f"],
env
);
shellCommandFactory(
"prod:pull",
"[TEST ONLY] Pull production services from the remote registry",
["docker compose --profile prod pull"],
env
);
shellCommandFactory(
"prod:up",
"[TEST ONLY] Start production services (foreground)",
["docker compose --profile prod-app up"],
env
);
shellCommandFactory(
"prod:up:d",
"[TEST ONLY] Start production services (background)",
["docker compose --profile prod-app up -d"],
env
);
program
.command("attach [service]")
.description("attach to a service")
.action(async (service: string | undefined) => {
const { run } = Deno;
let command = `docker compose ps`;
if (service) {
command = `${command} ${service}`;
}
console.log(ink.colorize(`<green>>>>>> Running: ${command}</green>`));
let cmd = command.split(" ");
const res = Deno.run({
cmd,
cwd: process.cwd(),
stdout: "piped",
stderr: "piped",
});
const output = await res.output(); // "piped" must be set
let services = new TextDecoder().decode(output).split("\n");
if (!services) {
console.error("No services available!");
return;
}
services.pop();
services = services.slice(1);
res.close(); // Don't forget to close it
let selService: string;
if (services.length > 1) {
selService = await Select.prompt({
message: `Select a service`,
options: services,
});
} else {
selService = services[0];
}
if (!selService) {
console.log(`Service ${service} is not available`);
return;
}
command = `docker attach ${selService.split(" ")[0]}`;
console.log(ink.colorize(`<green>>>>>> Running: ${command}</green>`));
console.log(
ink.colorize(
"<yellow>NOTE: you can detach from a container and leave it running using the CTRL-p CTRL-q key sequence.</yellow>"
)
);
cmd = command.split(" ");
const shellCmd = run({
cmd,
cwd: process.cwd(),
});
await shellCmd.status();
shellCmd.close();
});
program
.command("quit")
.description("Close docker command")
.action(() => {
process.exit(0);
});
/**
*
* @param name
* @param description
* @param commands you can pass one or more commands, they will be executed sequentially
* @returns
*/
function shellCommandFactory(
name: string,
description: string,
commands: string[],
env?: { [key: string]: string }
): Command {
return program
.command(name)
.description(
`${description}. Command: \n"${ink.colorize(
`<green>${commands.join(" && ")}</green>`
)}"\n`
)
.action(async (args: string[] | undefined) => {
const { run } = Deno;
for (const command of commands) {
console.log(ink.colorize(`<green>>>>>> Running: ${command}</green>`));
const cmd = command.split(" ");
if (Array.isArray(args)) {
cmd.push(...args);
}
const shellCmd = run({
cmd,
cwd: process.cwd(),
env: { ...process.env, ...env },
});
const status = await shellCmd.status();
if (!status.success) {
throw new Error(`Failed with error: ${status.code}, however,
it's not related to this Deno script directly. An error occurred within
the script called by the command itself`);
}
shellCmd.close();
}
});
}
async function checkDockerVersion() {
const { run } = Deno;
const dockerVerCmd = run({
cmd: ["docker", "compose", "version"],
cwd: process.cwd(),
env: { ...process.env, ...env },
stdout: "piped",
});
const output = await dockerVerCmd.output();
const status = await dockerVerCmd.status();
const outStr = new TextDecoder().decode(output);
if (!status.success) {
return 'not installed?'
}
const version = outStr.split(" ").pop()?.trim();
if (!version) return version;
if (!semver.gte(version, MIN_COMPOSE_VERSION)) {
return version;
}
return true;
}
async function main() {
while (true) {
const version = await checkDockerVersion();
if (version !== true) {
console.error(
ink.colorize(`<red>ERROR: Your docker compose version (${version}) must be higher or equal to ${MIN_COMPOSE_VERSION}. Please install the new version of docker compose and try again</red>`)
);
return false
}
if (Deno.args.length === 0) {
program.outputHelp();
const command = await Input.prompt({
message: "Enter the command:",
});
console.log(command);
await program.parseAsync(command.split(" "));
} else {
await program.parseAsync(Deno.args);
process.exit(0);
}
}
}
main();