feat: add MySQL database support

This commit is contained in:
reaper
2026-08-14 13:47:25 -05:00
parent 635f06b488
commit 55715d9fa4
6 changed files with 20 additions and 13 deletions
@@ -1,7 +1,7 @@
{ {
"id": "wordpress", "id": "wordpress",
"name": "WordPress", "name": "WordPress",
"version": "1.1.0", "version": "1.2.0",
"category": "application", "category": "application",
"description": "WordPress CMS provisioning and WP-CLI tooling.", "description": "WordPress CMS provisioning and WP-CLI tooling.",
"main": "main/index.cjs", "main": "main/index.cjs",
@@ -11,7 +11,7 @@
"defaults": { "docroot": "" }, "defaults": { "docroot": "" },
"settings": [], "settings": [],
"creation": { "creation": {
"databases": ["mariadb"], "databases": ["mariadb", "mysql"],
"intro": { "title": "WordPress install", "description": "Core downloads automatically and the project starts for setup.", "icon": "globe" }, "intro": { "title": "WordPress install", "description": "Core downloads automatically and the project starts for setup.", "icon": "globe" },
"setup": [ "setup": [
{ "id": "title", "label": "Site title", "type": "text", "default": "", "placeholder": "My WordPress Site", "icon": "title", "span": 2 }, { "id": "title", "label": "Site title", "type": "text", "default": "", "placeholder": "My WordPress Site", "icon": "title", "span": 2 },
@@ -1,6 +1,6 @@
{ {
"name": "@aurora/module-wordpress", "name": "@aurora/module-wordpress",
"version": "1.1.0", "version": "1.2.0",
"private": true, "private": true,
"description": "WordPress application module for Aurora Dockside", "description": "WordPress application module for Aurora Dockside",
"files": ["manifest.json", "main", "README.md"] "files": ["manifest.json", "main", "README.md"]
+6 -4
View File
@@ -17,7 +17,7 @@ type AuroraConfig = {
php: string php: string
node: string node: string
webserver: 'nginx' | 'apache' webserver: 'nginx' | 'apache'
database: 'mariadb' | 'postgres' database: 'mariadb' | 'mysql' | 'postgres'
databaseVersion: string databaseVersion: string
modules: string[] modules: string[]
moduleSettings?: Record<string, Record<string, string | number | boolean>> moduleSettings?: Record<string, Record<string, string | number | boolean>>
@@ -113,7 +113,9 @@ async function renderModuleService(module: AuroraModuleManifest, config: AuroraC
async function renderCompose(c: AuroraConfig): Promise<string> { async function renderCompose(c: AuroraConfig): Promise<string> {
const db = c.database === 'postgres' const db = c.database === 'postgres'
? ` db:\n image: postgres:${c.databaseVersion}\n environment:\n POSTGRES_DB: db\n POSTGRES_USER: db\n POSTGRES_PASSWORD: db\n volumes:\n - db_data:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U db -d db\"]\n interval: 3s\n timeout: 3s\n retries: 20` ? ` db:\n image: postgres:${c.databaseVersion}\n environment:\n POSTGRES_DB: db\n POSTGRES_USER: db\n POSTGRES_PASSWORD: db\n volumes:\n - db_data:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U db -d db\"]\n interval: 3s\n timeout: 3s\n retries: 20`
: ` db:\n image: mariadb:${c.databaseVersion}\n environment:\n MARIADB_DATABASE: db\n MARIADB_USER: db\n MARIADB_PASSWORD: db\n MARIADB_ROOT_PASSWORD: root\n volumes:\n - db_data:/var/lib/mysql\n healthcheck:\n test: [\"CMD\", \"healthcheck.sh\", \"--connect\", \"--innodb_initialized\"]\n interval: 3s\n timeout: 3s\n retries: 20` : c.database === 'mysql'
? ` db:\n image: mysql:${c.databaseVersion}\n environment:\n MYSQL_DATABASE: db\n MYSQL_USER: db\n MYSQL_PASSWORD: db\n MYSQL_ROOT_PASSWORD: root\n volumes:\n - db_data:/var/lib/mysql\n healthcheck:\n test: [\"CMD-SHELL\", \"mysqladmin ping -h localhost -uroot -proot --silent\"]\n interval: 3s\n timeout: 3s\n retries: 20`
: ` db:\n image: mariadb:${c.databaseVersion}\n environment:\n MARIADB_DATABASE: db\n MARIADB_USER: db\n MARIADB_PASSWORD: db\n MARIADB_ROOT_PASSWORD: root\n volumes:\n - db_data:/var/lib/mysql\n healthcheck:\n test: [\"CMD\", \"healthcheck.sh\", \"--connect\", \"--innodb_initialized\"]\n interval: 3s\n timeout: 3s\n retries: 20`
const coreServices: Record<string, AuroraModuleManifest> = { const coreServices: Record<string, AuroraModuleManifest> = {
redis: { id: 'redis', name: 'Redis', version: '1.0.0', category: 'service', description: '', dependencies: [], conflicts: [], settings: [], aurora: { core: CORE_VERSION, moduleApi: MODULE_API_VERSION }, compose: { service: 'redis', image: 'redis:8-alpine', ports: [6379] } }, redis: { id: 'redis', name: 'Redis', version: '1.0.0', category: 'service', description: '', dependencies: [], conflicts: [], settings: [], aurora: { core: CORE_VERSION, moduleApi: MODULE_API_VERSION }, compose: { service: 'redis', image: 'redis:8-alpine', ports: [6379] } },
mailpit: { id: 'mailpit', name: 'Mailpit', version: '1.0.0', category: 'tool', description: '', dependencies: [], conflicts: [], settings: [], aurora: { core: CORE_VERSION, moduleApi: MODULE_API_VERSION }, compose: { service: 'mailpit', image: 'axllent/mailpit:latest', ports: [8025, 1025] } } mailpit: { id: 'mailpit', name: 'Mailpit', version: '1.0.0', category: 'tool', description: '', dependencies: [], conflicts: [], settings: [], aurora: { core: CORE_VERSION, moduleApi: MODULE_API_VERSION }, compose: { service: 'mailpit', image: 'axllent/mailpit:latest', ports: [8025, 1025] } }
@@ -239,7 +241,7 @@ export async function updateEnvironment(root:string, updates:{phpVersion?:string
if(updates.webserverType === 'nginx' || updates.webserverType === 'nginx-fpm') c.webserver='nginx' if(updates.webserverType === 'nginx' || updates.webserverType === 'nginx-fpm') c.webserver='nginx'
if(updates.webserverType === 'apache' || updates.webserverType === 'apache-fpm') c.webserver='apache' if(updates.webserverType === 'apache' || updates.webserverType === 'apache-fpm') c.webserver='apache'
if(typeof updates.xdebugEnabled === 'boolean') c.xdebug=updates.xdebugEnabled if(typeof updates.xdebugEnabled === 'boolean') c.xdebug=updates.xdebugEnabled
if(updates.database){const [kind,version]=updates.database.split(':'); if(kind==='mariadb'||kind==='postgres'){c.database=kind;c.databaseVersion=version||c.databaseVersion}} if(updates.database){const [kind,version]=updates.database.split(':'); if(kind==='mariadb'||kind==='mysql'||kind==='postgres'){c.database=kind;c.databaseVersion=version||c.databaseVersion}}
if(updates.primaryProtocol === 'http' || updates.primaryProtocol === 'https') c.primaryProtocol = updates.primaryProtocol if(updates.primaryProtocol === 'http' || updates.primaryProtocol === 'https') c.primaryProtocol = updates.primaryProtocol
await writeConfig(root,c); await writeWebServerConfig(root,c); await writePhpDockerfile(root, c.xdebug === true) await writeConfig(root,c); await writeWebServerConfig(root,c); await writePhpDockerfile(root, c.xdebug === true)
} }
@@ -331,7 +333,7 @@ export async function scaffoldApplicationModule(_name: string, moduleId: string)
export async function getProjectRoot(name:string):Promise<string>{const r=await loadRegistry();if(!r.projects[name])throw new Error(`Project ${name} not found`);return r.projects[name]} export async function getProjectRoot(name:string):Promise<string>{const r=await loadRegistry();if(!r.projects[name])throw new Error(`Project ${name} not found`);return r.projects[name]}
export async function getProjectConfigByRoot(root: string): Promise<{ database: 'mariadb' | 'postgres'; databaseVersion: string; name: string }> { export async function getProjectConfigByRoot(root: string): Promise<{ database: 'mariadb' | 'mysql' | 'postgres'; databaseVersion: string; name: string }> {
const config = await readConfig(root) const config = await readConfig(root)
return { database: config.database, databaseVersion: config.databaseVersion, name: config.name } return { database: config.database, databaseVersion: config.databaseVersion, name: config.name }
} }
+7 -2
View File
@@ -16,18 +16,23 @@ function safeSnapshotName(value?: string): string {
return safe || fallback return safe || fallback
} }
function dbCommand(type: 'mariadb' | 'postgres', mode: 'dump' | 'restore'): { command: string; args: string[] } { function dbCommand(type: 'mariadb' | 'mysql' | 'postgres', mode: 'dump' | 'restore'): { command: string; args: string[] } {
if (type === 'postgres') { if (type === 'postgres') {
return mode === 'dump' return mode === 'dump'
? { command: 'pg_dump', args: ['-U', 'db', '-d', 'db', '--clean', '--if-exists'] } ? { command: 'pg_dump', args: ['-U', 'db', '-d', 'db', '--clean', '--if-exists'] }
: { command: 'psql', args: ['-U', 'db', '-d', 'db', '-v', 'ON_ERROR_STOP=1'] } : { command: 'psql', args: ['-U', 'db', '-d', 'db', '-v', 'ON_ERROR_STOP=1'] }
} }
if (type === 'mysql') {
return mode === 'dump'
? { command: 'mysqldump', args: ['-udb', '-pdb', '--single-transaction', '--routines', '--triggers', 'db'] }
: { command: 'mysql', args: ['-udb', '-pdb', 'db'] }
}
return mode === 'dump' return mode === 'dump'
? { command: 'mariadb-dump', args: ['-udb', '-pdb', '--single-transaction', '--routines', '--triggers', 'db'] } ? { command: 'mariadb-dump', args: ['-udb', '-pdb', '--single-transaction', '--routines', '--triggers', 'db'] }
: { command: 'mariadb', args: ['-udb', '-pdb', 'db'] } : { command: 'mariadb', args: ['-udb', '-pdb', 'db'] }
} }
function runDatabasePipe(root: string, type: 'mariadb' | 'postgres', mode: 'dump' | 'restore', filePath: string): Promise<void> { function runDatabasePipe(root: string, type: 'mariadb' | 'mysql' | 'postgres', mode: 'dump' | 'restore', filePath: string): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const db = dbCommand(type, mode) const db = dbCommand(type, mode)
const child = spawn('docker', ['compose', '-f', composeFile(root), 'exec', '-T', 'db', db.command, ...db.args], { const child = spawn('docker', ['compose', '-f', composeFile(root), 'exec', '-T', 'db', db.command, ...db.args], {
@@ -42,7 +42,7 @@ export function CreateProjectModal({ onClose }: { onClose: () => void }): React.
const [phpVersion, setPhpVersion] = useState('8.4') const [phpVersion, setPhpVersion] = useState('8.4')
const [nodeVersion, setNodeVersion] = useState('24') const [nodeVersion, setNodeVersion] = useState('24')
const [webServer, setWebServer] = useState<'nginx' | 'apache'>('nginx') const [webServer, setWebServer] = useState<'nginx' | 'apache'>('nginx')
const [database, setDatabase] = useState<'mariadb' | 'postgres'>('mariadb') const [database, setDatabase] = useState<'mariadb' | 'mysql' | 'postgres'>('mariadb')
const [databaseVersion, setDatabaseVersion] = useState('11.8') const [databaseVersion, setDatabaseVersion] = useState('11.8')
const [adminer, setAdminer] = useState(true) const [adminer, setAdminer] = useState(true)
const [redis, setRedis] = useState(false) const [redis, setRedis] = useState(false)
@@ -275,7 +275,7 @@ export function CreateProjectModal({ onClose }: { onClose: () => void }): React.
<div><label className={labelClass}>PHP</label><select className={fieldClass} value={phpVersion} onChange={(e)=>setPhpVersion(e.target.value)}>{['8.2','8.3','8.4','8.5'].map(v=><option key={v}>{v}</option>)}</select></div> <div><label className={labelClass}>PHP</label><select className={fieldClass} value={phpVersion} onChange={(e)=>setPhpVersion(e.target.value)}>{['8.2','8.3','8.4','8.5'].map(v=><option key={v}>{v}</option>)}</select></div>
<div><label className={labelClass}>Node.js</label><select className={fieldClass} value={nodeVersion} onChange={(e)=>setNodeVersion(e.target.value)}>{['20','22','24'].map(v=><option key={v}>{v}</option>)}</select></div> <div><label className={labelClass}>Node.js</label><select className={fieldClass} value={nodeVersion} onChange={(e)=>setNodeVersion(e.target.value)}>{['20','22','24'].map(v=><option key={v}>{v}</option>)}</select></div>
<div><label className={labelClass}>Web server</label><select className={fieldClass} value={webServer} onChange={(e)=>setWebServer(e.target.value as 'nginx'|'apache')}><option value="nginx">nginx</option><option value="apache">Apache</option></select></div> <div><label className={labelClass}>Web server</label><select className={fieldClass} value={webServer} onChange={(e)=>setWebServer(e.target.value as 'nginx'|'apache')}><option value="nginx">nginx</option><option value="apache">Apache</option></select></div>
<div><label className={labelClass}>Database</label><select className={fieldClass} value={`${database}:${databaseVersion}`} onChange={(e)=>{const [kind,version]=e.target.value.split(':');setDatabase(kind as 'mariadb'|'postgres');setDatabaseVersion(version)}}>{selectedModule?.creation?.databases?.includes('mariadb') !== false && <><option value="mariadb:11.8">MariaDB 11.8</option><option value="mariadb:10.11">MariaDB 10.11</option></>}{selectedModule?.creation?.databases?.includes('postgres') !== false && <><option value="postgres:17">PostgreSQL 17</option><option value="postgres:16">PostgreSQL 16</option></>}</select></div> <div><label className={labelClass}>Database</label><select className={fieldClass} value={`${database}:${databaseVersion}`} onChange={(e)=>{const [kind,version]=e.target.value.split(':');setDatabase(kind as 'mariadb'|'mysql'|'postgres');setDatabaseVersion(version)}}>{selectedModule?.creation?.databases?.includes('mariadb') !== false && <><option value="mariadb:11.8">MariaDB 11.8</option><option value="mariadb:10.11">MariaDB 10.11</option></>}{selectedModule?.creation?.databases?.includes('mysql') !== false && <><option value="mysql:8.4">MySQL 8.4</option><option value="mysql:8.0">MySQL 8.0</option></>}{selectedModule?.creation?.databases?.includes('postgres') !== false && <><option value="postgres:17">PostgreSQL 17</option><option value="postgres:16">PostgreSQL 16</option></>}</select></div>
<div className="grid grid-cols-2 gap-2 pt-5"> <div className="grid grid-cols-2 gap-2 pt-5">
{[['Adminer',adminer,setAdminer],['Redis',redis,setRedis],['Mailpit',mailpit,setMailpit],['Xdebug',xdebug,setXdebug]].map(([label,value,setter])=><label key={label as string} className="flex items-center gap-2 text-xs font-medium"><input type="checkbox" checked={value as boolean} onChange={(e)=>(setter as (v:boolean)=>void)(e.target.checked)} />{label as string}</label>)} {[['Adminer',adminer,setAdminer],['Redis',redis,setRedis],['Mailpit',mailpit,setMailpit],['Xdebug',xdebug,setXdebug]].map(([label,value,setter])=><label key={label as string} className="flex items-center gap-2 text-xs font-medium"><input type="checkbox" checked={value as boolean} onChange={(e)=>(setter as (v:boolean)=>void)(e.target.checked)} />{label as string}</label>)}
</div> </div>
+2 -2
View File
@@ -88,7 +88,7 @@ export interface AuroraStackOptions {
phpVersion: string phpVersion: string
nodeVersion: string nodeVersion: string
webServer: 'nginx' | 'apache' webServer: 'nginx' | 'apache'
database: 'mariadb' | 'postgres' database: 'mariadb' | 'mysql' | 'postgres'
databaseVersion: string databaseVersion: string
adminer: boolean adminer: boolean
redis: boolean redis: boolean
@@ -143,7 +143,7 @@ export interface AuroraModuleManifest {
settings: AuroraModuleSetting[] settings: AuroraModuleSetting[]
aurora: { core: string; moduleApi: string } aurora: { core: string; moduleApi: string }
creation?: { creation?: {
databases?: Array<'mariadb' | 'postgres'> databases?: Array<'mariadb' | 'mysql' | 'postgres'>
setup?: AuroraModuleSetting[] setup?: AuroraModuleSetting[]
intro?: { title: string; description: string; icon?: string } intro?: { title: string; description: string; icon?: string }
} }