Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker improvements #5946

Merged
merged 20 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.env
icon_cache
logs
dist
5 changes: 2 additions & 3 deletions .env.test
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
TZ="UTC"
ROBOCHIMP_DATABASE_URL="postgresql://postgres:postgres@localhost:5435/robochimp_integration_test?connection_limit=500&pool_timeout=0&schema=public"
DATABASE_URL="postgresql://postgres:postgres@localhost:5435/osb_integration_test?connection_limit=500&pool_timeout=0&schema=public"
CLIENT_ID=111398433321891634
BOT_TOKEN=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
TEST=true
TEST=true
CI=true
25 changes: 21 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
services:
osb:
db:
image: postgres:16-alpine
command: -c 'max_connections=1000'
command: -c 'max_connections=1000' -c 'log_connections=on' -c 'log_disconnections=on'
restart: always
container_name: osb_database
ports:
- "5435:3001"
- "5435:5435"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PGPORT: 3001
PGPORT: 5435
volumes:
- postgres_data:/var/lib/postgresql/data

app:
build:
context: .
args:
GIT_BRANCH: ${GIT_BRANCH}
depends_on:
- db
environment:
ROBOCHIMP_DATABASE_URL: postgresql://postgres:postgres@db:5435/robochimp_integration_test?connection_limit=500&pool_timeout=0&schema=public
DATABASE_URL: postgresql://postgres:postgres@db:5435/osb_integration_test?connection_limit=500&pool_timeout=0&schema=public
WAIT_HOSTS: db:5435

volumes:
postgres_data:
32 changes: 32 additions & 0 deletions dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM node:20.15.0-alpine AS base
WORKDIR /usr/src/app
ENV CI=true
RUN apk add --no-cache dumb-init python3 g++ make git
RUN corepack enable

COPY yarn.lock package.json .yarnrc.yml ./
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The COPY command is used without specifying ownership, which might lead to files being owned by the root user. This can pose a security risk if the application is expected to run as a non-root user but has access to root-owned files. Consider using the --chown=node:node option with the COPY command to explicitly set file ownership.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the .yarn/ directory copy step could potentially break the yarn install command if the project relies on specific configurations or patches stored in this directory. Consider restoring this step if it's crucial for the build process.

COPY .yarn/ .yarn/

ENTRYPOINT ["dumb-init", "--"]


FROM base AS dependencies
RUN yarn install --immutable


FROM base AS build-run
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NODE_ENV is set to "development" in the Dockerfile, which is typically not recommended for production builds as it can expose more verbose error messages and potentially sensitive stack traces. Consider using a production setting or managing this through environment variables passed at runtime.

ENV NODE_ENV="development"
ENV NODE_OPTIONS="--enable-source-maps --max_old_space_size=4096"

COPY --from=dependencies /usr/src/app/node_modules ./node_modules
COPY . .

ENV CI=true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .env.test file is being copied and renamed to .env in the Dockerfile. This is generally not recommended for production environments as test configurations might include sensitive defaults or settings not suitable for production. Consider using environment-specific configuration files or managing these settings through environment variables.

RUN cp .env.test .env

RUN yarn run build:esbuild

ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.9.0/wait /wait
RUN chmod +x /wait

CMD /wait && yarn prisma db push --schema='./prisma/robochimp.prisma' && yarn prisma db push --schema='./prisma/schema.prisma' && yarn vitest run --config vitest.integration.config.mts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CMD instruction in the Dockerfile is executing multiple commands which include schema migrations and tests. This is not recommended for a Dockerfile that is meant to run a production application, as it should only start the application. Consider separating these tasks into different stages or scripts that are not part of the Docker container's startup command.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"test:unit": "vitest run --coverage --config vitest.unit.config.mts",
"test:watch": "vitest --config vitest.unit.config.mts --coverage",
"test:integration": "tsx ./src/scripts/integration-tests.ts",
"watch": "tsc -w -p src"
"watch": "tsc -w -p src",
"build:esbuild": "esbuild src/index.ts src/lib/workers/kill.worker.ts src/lib/workers/finish.worker.ts src/lib/workers/casket.worker.ts --bundle --outdir=dist --platform=node --loader:.node=file"
},
"dependencies": {
"@napi-rs/canvas": "^0.1.53",
Expand Down Expand Up @@ -51,6 +52,7 @@
"@types/node-fetch": "^2.6.1",
"@vitest/coverage-v8": "^1.6.0",
"concurrently": "^8.2.2",
"esbuild": "0.21.5",
"fast-glob": "^3.3.2",
"prettier": "^3.3.2",
"prisma": "^5.16.1",
Expand All @@ -61,5 +63,8 @@
"engines": {
"node": "20.15.0"
},
"packageManager": "[email protected]"
"packageManager": "[email protected]",
"resolutions": {
"esbuild": "0.21.5"
}
}
3 changes: 1 addition & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import './lib/globals';
import './lib/data/itemAliases';
import './lib/data/trophies';
import './lib/globals';
import './lib/crons';
import './lib/MUser';
import './lib/util/transactItemsFromBank';
Expand Down
8 changes: 5 additions & 3 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,11 +534,12 @@ const globalConfigSchema = z.object({
clientID: z.string().min(10).max(25),
geAdminChannelID: z.string().default(''),
redisPort: z.coerce.number().int().optional(),
botToken: z.string().min(1)
botToken: z.string().min(1),
isCI: z.coerce.boolean().default(false)
});
dotenv.config({ path: path.resolve(process.cwd(), process.env.TEST ? '.env.test' : '.env') });

if (!process.env.BOT_TOKEN) {
if (!process.env.BOT_TOKEN && !process.env.CI) {
throw new Error(
`You need to specify the BOT_TOKEN environment variable, copy your bot token from your config.ts and put it in the ".env" file like so:\n\nBOT_TOKEN=your_token_here`
);
Expand All @@ -548,7 +549,8 @@ export const globalConfig = globalConfigSchema.parse({
clientID: process.env.CLIENT_ID,
geAdminChannelID: process.env.GE_ADMIN_CHANNEL_ID,
redisPort: process.env.REDIS_PORT,
botToken: process.env.BOT_TOKEN
botToken: process.env.BOT_TOKEN,
isCI: process.env.CI
});

export const ONE_TRILLION = 1_000_000_000_000;
Expand Down
67 changes: 67 additions & 0 deletions src/lib/data/itemAliases.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { modifyItem } from '@oldschoolgg/toolkit';
import { Items } from 'oldschooljs';
import { itemNameMap } from 'oldschooljs/dist/structures/Items';
import { cleanString } from 'oldschooljs/dist/util/cleanString';
import { resolveItems } from 'oldschooljs/dist/util/util';

export function setItemAlias(id: number, name: string | string[], rename = true) {
const existingItem = Items.get(id);
Expand Down Expand Up @@ -298,3 +300,68 @@ setItemAlias(25_922, 'Antique lamp (hard ca)');
setItemAlias(25_923, 'Antique lamp (elite ca)');
setItemAlias(25_924, 'Antique lamp (master ca)');
setItemAlias(25_925, 'Antique lamp (grandmaster ca)');

/**
* Trophies
*/

// BSO (Twisted) trophies
setItemAlias(24_372, 'BSO dragon trophy');
setItemAlias(24_374, 'BSO rune trophy');
setItemAlias(24_376, 'BSO adamant trophy');
setItemAlias(24_378, 'BSO mithril trophy');
setItemAlias(24_380, 'BSO steel trophy');
setItemAlias(24_382, 'BSO iron trophy');
setItemAlias(24_384, 'BSO bronze trophy');

// Comp. trophies
setItemAlias(25_042, 'Comp. dragon trophy');
setItemAlias(25_044, 'Comp. rune trophy');
setItemAlias(25_046, 'Comp. adamant trophy');
setItemAlias(25_048, 'Comp. mithril trophy');
setItemAlias(25_050, 'Comp. steel trophy');
setItemAlias(25_052, 'Comp. iron trophy');
setItemAlias(25_054, 'Comp. bronze trophy');

// Placeholder trophies
setItemAlias(26_515, 'Placeholder dragon trophy');
setItemAlias(26_513, 'Placeholder rune trophy');
setItemAlias(26_511, 'Placeholder adamant trophy');
setItemAlias(26_509, 'Placeholder mithril trophy');
setItemAlias(26_507, 'Placeholder steel trophy');
setItemAlias(26_505, 'Placeholder iron trophy');
setItemAlias(26_503, 'Placeholder bronze trophy');

export const allTrophyItems = resolveItems([
'BSO dragon trophy',
'BSO rune trophy',
'BSO adamant trophy',
'BSO mithril trophy',
'BSO steel trophy',
'BSO iron trophy',
'BSO bronze trophy',
'Comp. dragon trophy',
'Comp. rune trophy',
'Comp. adamant trophy',
'Comp. mithril trophy',
'Comp. steel trophy',
'Comp. iron trophy',
'Comp. bronze trophy',
'Placeholder dragon trophy',
'Placeholder rune trophy',
'Placeholder adamant trophy',
'Placeholder mithril trophy',
'Placeholder steel trophy',
'Placeholder iron trophy',
'Placeholder bronze trophy'
]);

for (const item of allTrophyItems) {
modifyItem(item, {
tradeable: false,
tradeable_on_ge: false,
customItemData: {
cantBeSacrificed: true
}
});
}
65 changes: 0 additions & 65 deletions src/lib/data/trophies.ts

This file was deleted.

14 changes: 0 additions & 14 deletions src/lib/settings/prisma.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
import { isMainThread } from 'node:worker_threads';
import type { Activity, Prisma } from '@prisma/client';
import { activity_type_enum } from '@prisma/client';

import { production } from '../../config';
import type { ActivityTaskData } from '../types/minions';
import { sqlLog } from '../util/logger';

export const queryCountStore = { value: 0 };

if (isMainThread) {
// @ts-ignore ignore
prisma.$on('query' as any, (_query: any) => {
const query = _query as Prisma.QueryEvent;
if (!production) {
sqlLog(query.query);
}
queryCountStore.value++;
});
}

export function convertStoredActivityToFlatActivity(activity: Activity): ActivityTaskData {
return {
...(activity.data as Prisma.JsonObject),
Expand Down
6 changes: 3 additions & 3 deletions src/lib/workers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ export type FinishWorkerReturn = Promise<
const maxThreads = production ? 3 : 1;

const finishWorker = new Piscina({
filename: resolve(__dirname.replace('src', 'dist'), 'finish.worker.js'),
filename: resolve(__dirname, 'finish.worker.js'),
maxThreads
});
const killWorker = new Piscina({
filename: resolve(__dirname.replace('src', 'dist'), 'kill.worker.js'),
filename: resolve(__dirname, 'kill.worker.js'),
maxThreads
});
const casketWorker = new Piscina({
filename: resolve(__dirname.replace('src', 'dist'), 'casket.worker.js'),
filename: resolve(__dirname, 'casket.worker.js'),
maxThreads
});

Expand Down
28 changes: 12 additions & 16 deletions src/scripts/integration-tests.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
import { execSync } from 'node:child_process';
import path from 'node:path';
import { Stopwatch } from '@oldschoolgg/toolkit';
import { config } from 'dotenv';

import { execAsync } from './scriptUtil';

async function main() {
const stopwatch = new Stopwatch();
try {
execSync('docker compose up -d --wait', { stdio: 'inherit' });
await execAsync(['docker compose up -d --wait', 'npm install -g wait-on']);
stopwatch.check('Docker compose finished.');

execSync('npm install -g wait-on', { stdio: 'inherit' });
execSync('wait-on tcp:5435 -t 10s', { stdio: 'inherit' });
await execAsync('wait-on tcp:5435 -t 10s');

const env = { ...process.env, ...config({ path: path.resolve('.env.test') }).parsed };
execSync('yarn prisma db push --schema="./prisma/schema.prisma"', { stdio: 'inherit', env });
execSync('yarn prisma db push --schema="./prisma/robochimp.prisma"', { stdio: 'inherit', env });
await execAsync([
'yarn prisma db push --schema="./prisma/schema.prisma"',
'yarn prisma db push --schema="./prisma/robochimp.prisma"'
]);
stopwatch.check('Finished prisma pushing.');

execSync('yarn build:tsc', { stdio: 'inherit' });
await execAsync('yarn build:tsc');
stopwatch.check('Finished building, starting tests.');

console.log('Starting tests...');
const runs = 1;
for (let i = 0; i < runs; i++) {
console.log(`Starting run ${i + 1}/${runs}`);
execSync('vitest run --config vitest.integration.config.mts', {
stdio: 'inherit',
encoding: 'utf-8'
});
await execAsync('vitest run --config vitest.integration.config.mts');
console.log(`Finished run ${i + 1}/${runs}`);
}
} catch (err) {
console.log(execSync('docker-compose logs', { encoding: 'utf-8' }));
console.log(await execAsync('docker-compose logs'));
console.error(err);
throw new Error(err as any);
} finally {
execSync('docker-compose down', { stdio: 'inherit' });
await execAsync('docker-compose down');
stopwatch.check('Finished.');
}
}
Expand Down
Loading
Loading