Merge pull request #500 from getmaxun/auto-migrate
feat: automate db migrations
This commit is contained in:
@@ -11,6 +11,7 @@ COPY public ./public
|
||||
COPY server ./server
|
||||
COPY tsconfig.json ./
|
||||
COPY server/tsconfig.json ./server/
|
||||
COPY .sequelizerc ./
|
||||
# COPY server/start.sh ./
|
||||
|
||||
# Install dependencies
|
||||
@@ -41,11 +42,18 @@ RUN apt-get update && apt-get install -y \
|
||||
libxext6 \
|
||||
libxi6 \
|
||||
libxtst6 \
|
||||
postgresql-client \
|
||||
netcat-openbsd \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p /tmp/.X11-unix && chmod 1777 /tmp/.X11-unix
|
||||
|
||||
COPY server/docker-entrypoint.sh /app/
|
||||
RUN chmod +x /app/docker-entrypoint.sh
|
||||
|
||||
# Expose the backend port
|
||||
EXPOSE ${BACKEND_PORT:-8080}
|
||||
|
||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||
|
||||
# Start the backend using the start script
|
||||
CMD ["npm", "run", "server"]
|
||||
|
||||
33
server/docker-entrypoint.sh
Normal file
33
server/docker-entrypoint.sh
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Function to wait for PostgreSQL
|
||||
wait_for_postgres() {
|
||||
echo "Waiting for PostgreSQL at $DB_HOST:$DB_PORT..."
|
||||
|
||||
max_retries=30
|
||||
retries=0
|
||||
|
||||
while ! nc -z $DB_HOST $DB_PORT; do
|
||||
retries=$((retries+1))
|
||||
if [ $retries -eq $max_retries ]; then
|
||||
echo "Error: PostgreSQL not available after $max_retries attempts. Continuing anyway..."
|
||||
break
|
||||
fi
|
||||
echo "PostgreSQL not available yet (attempt $retries/$max_retries), retrying..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $retries -lt $max_retries ]; then
|
||||
echo "PostgreSQL is ready!"
|
||||
fi
|
||||
}
|
||||
|
||||
# Wait for PostgreSQL to be ready
|
||||
wait_for_postgres
|
||||
|
||||
# Run the application with migrations before startup
|
||||
NODE_OPTIONS="--max-old-space-size=4096" node -e "require('./server/src/db/migrate')().then(() => { console.log('Migration process completed.'); })"
|
||||
|
||||
# Run the server normally
|
||||
exec "$@"
|
||||
42
server/src/db/config/database.js
Normal file
42
server/src/db/config/database.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config({ path: './.env' });
|
||||
|
||||
// Validate required environment variables
|
||||
const requiredEnvVars = ['DB_USER', 'DB_PASSWORD', 'DB_NAME', 'DB_HOST', 'DB_PORT'];
|
||||
requiredEnvVars.forEach(envVar => {
|
||||
if (!process.env[envVar]) {
|
||||
console.error(`Error: Environment variable ${envVar} is not set.`);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = {
|
||||
development: {
|
||||
username: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
dialect: 'postgres',
|
||||
logging: console.log,
|
||||
},
|
||||
test: {
|
||||
username: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
dialect: 'postgres',
|
||||
logging: false,
|
||||
},
|
||||
production: {
|
||||
username: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
dialect: 'postgres',
|
||||
logging: false,
|
||||
}
|
||||
};
|
||||
30
server/src/db/migrate.js
Normal file
30
server/src/db/migrate.js
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import db from './models/index.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
async function runMigrations() {
|
||||
try {
|
||||
console.log('Testing database connection...');
|
||||
await db.sequelize.authenticate();
|
||||
console.log('Database connection established successfully.');
|
||||
|
||||
console.log('Running database migrations...');
|
||||
execSync('npx sequelize-cli db:migrate', {
|
||||
stdio: 'inherit',
|
||||
cwd: path.resolve(__dirname, '../../..')
|
||||
});
|
||||
console.log('Migrations completed successfully');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Migration error:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = runMigrations;
|
||||
59
server/src/db/models/index.js
Normal file
59
server/src/db/models/index.js
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import Sequelize from 'sequelize';
|
||||
import databaseConfig from '../config/database.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const basename = path.basename(__filename);
|
||||
const env = process.env.NODE_ENV || 'development';
|
||||
const config = databaseConfig[env];
|
||||
const db = {};
|
||||
|
||||
let sequelize;
|
||||
if (config.use_env_variable) {
|
||||
try {
|
||||
sequelize = new Sequelize(process.env[config.use_env_variable], config);
|
||||
console.log(`Connected to database using ${config.use_env_variable}`);
|
||||
} catch (error) {
|
||||
console.error('Unable to connect to the database using environment variable:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
sequelize = new Sequelize(config.database, config.username, config.password, config);
|
||||
console.log(`Connected to database: ${config.database}`);
|
||||
} catch (error) {
|
||||
console.error('Unable to connect to the database:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fs
|
||||
.readdirSync(__dirname)
|
||||
.filter(file => {
|
||||
return (
|
||||
file.indexOf('.') !== 0 &&
|
||||
file !== basename &&
|
||||
file.slice(-3) === '.js' &&
|
||||
file.indexOf('.test.js') === -1
|
||||
);
|
||||
})
|
||||
.forEach(file => {
|
||||
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
|
||||
db[model.name] = model;
|
||||
});
|
||||
|
||||
Object.keys(db).forEach(modelName => {
|
||||
if (db[modelName].associate) {
|
||||
db[modelName].associate(db);
|
||||
}
|
||||
});
|
||||
|
||||
db.sequelize = sequelize;
|
||||
db.Sequelize = Sequelize;
|
||||
|
||||
module.exports = db;
|
||||
Reference in New Issue
Block a user