Command and workspace structure refactor
This commit is contained in:
parent
513862648d
commit
1b8da1f48f
|
@ -14,10 +14,9 @@ RUN apt-get update \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY \
|
COPY \
|
||||||
export-fixtures.sh \
|
myvc-dump.sh \
|
||||||
export-structure.sh \
|
myvc-push.sh \
|
||||||
apply-changes.sh \
|
|
||||||
db.ini \
|
db.ini \
|
||||||
/usr/local/bin/
|
/usr/local/bin/
|
||||||
|
|
||||||
WORKDIR /workdir
|
WORKDIR /workspace
|
||||||
|
|
|
@ -3,23 +3,22 @@ FROM myvc/server
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
COPY \
|
COPY \
|
||||||
dump/structure.local.sql \
|
|
||||||
dump/structure.sql \
|
|
||||||
dump/fixtures.sql \
|
|
||||||
myvc.config.json \
|
myvc.config.json \
|
||||||
|
myvc.structure.sql \
|
||||||
|
.dump.sql \
|
||||||
./
|
./
|
||||||
RUN gosu mysql docker-init.sh \
|
RUN gosu mysql docker-init.sh \
|
||||||
&& docker-dump.sh structure.local \
|
&& docker-dump.sh myvc.structure \
|
||||||
&& docker-dump.sh structure \
|
&& docker-dump.sh .dump \
|
||||||
&& docker-dump.sh fixtures \
|
|
||||||
&& gosu mysql docker-temp-stop.sh
|
&& gosu mysql docker-temp-stop.sh
|
||||||
|
|
||||||
|
COPY routines ./routines
|
||||||
COPY changes ./changes
|
COPY changes ./changes
|
||||||
COPY dump/fixtures.local.sql ./
|
COPY myvc.fixtures.sql ./
|
||||||
ARG STAMP=unknown
|
ARG STAMP=unknown
|
||||||
RUN gosu mysql docker-temp-start.sh \
|
RUN gosu mysql docker-temp-start.sh \
|
||||||
&& apply-changes.sh \
|
&& myvc-push.sh \
|
||||||
&& docker-dump.sh fixtures.local \
|
&& docker-dump.sh myvc.fixtures \
|
||||||
&& gosu mysql docker-temp-stop.sh
|
&& gosu mysql docker-temp-stop.sh
|
||||||
|
|
||||||
RUN echo "[INFO] -> Import finished" \
|
RUN echo "[INFO] -> Import finished" \
|
||||||
|
|
|
@ -20,7 +20,7 @@ COPY \
|
||||||
docker/docker-temp-stop.sh \
|
docker/docker-temp-stop.sh \
|
||||||
docker/docker-dump.sh \
|
docker/docker-dump.sh \
|
||||||
docker/docker-start.sh \
|
docker/docker-start.sh \
|
||||||
apply-changes.sh \
|
myvc-push.sh \
|
||||||
/usr/local/bin/
|
/usr/local/bin/
|
||||||
|
|
||||||
RUN mkdir /mysql-data \
|
RUN mkdir /mysql-data \
|
||||||
|
|
38
README.md
38
README.md
|
@ -21,33 +21,33 @@ Required applications.
|
||||||
It's recommended to install the package globally.
|
It's recommended to install the package globally.
|
||||||
```text
|
```text
|
||||||
# npm install -g myvc
|
# npm install -g myvc
|
||||||
$ myvc [action]
|
$ myvc [command]
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also install locally and use the *npx* command to execute it.
|
You can also install locally and use the *npx* command to execute it.
|
||||||
```text
|
```text
|
||||||
$ npm install myvc
|
$ npm install myvc
|
||||||
$ npx myvc [action]
|
$ npx myvc [command]
|
||||||
```
|
```
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
Execute *myvc* with the desired action.
|
Execute *myvc* with the desired command.
|
||||||
```text
|
```text
|
||||||
$ myvc [-w|--workdir] [-e|--env] [-h|--help] action
|
$ myvc [-w|--workspace] [-e|--env] [-h|--help] command
|
||||||
```
|
```
|
||||||
The default working directory is the current one and unless otherwise indicated,
|
The default working directory is the current one and unless otherwise indicated,
|
||||||
the default environment is *production*.
|
the default environment is *production*.
|
||||||
|
|
||||||
Available actions are:
|
Available commands are:
|
||||||
* **structure**: Export database structure.
|
|
||||||
* **fixtures**: Export database fixtures.
|
* **pull**: Exports database routines into workspace.
|
||||||
* **routines**: Export database routines.
|
* **push**: Apply changes into database, uses *test* environment by default.
|
||||||
* **apply**: Apply changes into database, uses *local* environment by default.
|
* **dump**: Export database structure and fixtures.
|
||||||
* **run**: Builds and starts local database server container.
|
* **run**: Builds and starts local database server container.
|
||||||
* **start**: Starts local database server container.
|
* **start**: Starts local database server container.
|
||||||
|
|
||||||
Each action can have its own specific commandline options.
|
Each command can have its own specific commandline options.
|
||||||
|
|
||||||
## Basic information
|
## Basic information
|
||||||
|
|
||||||
|
@ -56,8 +56,8 @@ includes the tables where MyVC stores information about applied versions.
|
||||||
|
|
||||||
Create *myvc.config.json* main configuration file at the root of your project
|
Create *myvc.config.json* main configuration file at the root of your project
|
||||||
folder, this file should include the project codename and schemas/tables wich
|
folder, this file should include the project codename and schemas/tables wich
|
||||||
are exported when you use *structure*, *fixtures* or *routines* actions. You
|
are exported when you use *pull*or *dump* commands. You have an example of a
|
||||||
have an example of a configuration file in the root folder of this project.
|
configuration file in the root folder of this project.
|
||||||
|
|
||||||
### Environments
|
### Environments
|
||||||
|
|
||||||
|
@ -70,17 +70,11 @@ db.[environment].ini
|
||||||
|
|
||||||
### Dumps
|
### Dumps
|
||||||
|
|
||||||
Structure and fixture dumps will be created inside *dump* folder.
|
Structure and fixture dumps will be created into hidden file *.dump.sql*. You
|
||||||
|
can also create your local fixture and structure files.
|
||||||
|
|
||||||
* *structure.sql*
|
* *myvc.structure.sql*
|
||||||
* *fixtures.sql*
|
* *myvc.fixtures.sql*
|
||||||
|
|
||||||
### Local
|
|
||||||
|
|
||||||
You can also create your local fixture and structure files inside *dump* folder.
|
|
||||||
|
|
||||||
* *structure.local.sql*
|
|
||||||
* *fixtures.local.sql*
|
|
||||||
|
|
||||||
### Routines
|
### Routines
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ const path = require('path');
|
||||||
const execFile = require('child_process').execFile;
|
const execFile = require('child_process').execFile;
|
||||||
const spawn = require('child_process').spawn;
|
const spawn = require('child_process').spawn;
|
||||||
|
|
||||||
module.exports = async function(command, workdir, ...args) {
|
module.exports = async function(command, workspace, ...args) {
|
||||||
const buildArgs = [
|
const buildArgs = [
|
||||||
'build',
|
'build',
|
||||||
'-t', 'myvc/client',
|
'-t', 'myvc/client',
|
||||||
|
@ -20,7 +20,7 @@ module.exports = async function(command, workdir, ...args) {
|
||||||
|
|
||||||
let runArgs = [
|
let runArgs = [
|
||||||
'run',
|
'run',
|
||||||
'-v', `${workdir}:/workdir`,
|
'-v', `${workspace}:/workspace`,
|
||||||
'myvc/client',
|
'myvc/client',
|
||||||
command
|
command
|
||||||
];
|
];
|
||||||
|
|
|
@ -149,7 +149,7 @@ module.exports = class Docker {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elapsedTime >= maxInterval)
|
if (elapsedTime >= maxInterval)
|
||||||
reject(new Error(`Container initialized whithin ${elapsedTime / 1000} secs`));
|
reject(new Error(`Container not initialized whithin ${elapsedTime / 1000} secs`));
|
||||||
else
|
else
|
||||||
setTimeout(bindedChecker, interval);
|
setTimeout(bindedChecker, interval);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
CONFIG_FILE=$1
|
|
||||||
INI_FILE=$2
|
|
||||||
DUMP_FILE="dump/structure.sql"
|
|
||||||
|
|
||||||
echo "SELECT 1;" | mysql --defaults-file="$INI_FILE" >> /dev/null
|
|
||||||
SCHEMAS=( $(jq -r ".schemas[]" "$CONFIG_FILE") )
|
|
||||||
|
|
||||||
mysqldump \
|
|
||||||
--defaults-file="$INI_FILE" \
|
|
||||||
--default-character-set=utf8 \
|
|
||||||
--no-data \
|
|
||||||
--comments \
|
|
||||||
--triggers --routines --events \
|
|
||||||
--databases \
|
|
||||||
${SCHEMAS[@]} \
|
|
||||||
| sed 's/ AUTO_INCREMENT=[0-9]* //g' \
|
|
||||||
> "$DUMP_FILE"
|
|
76
index.js
76
index.js
|
@ -13,12 +13,12 @@ const argv = process.argv.slice(2);
|
||||||
const cliOpts = getopts(argv, {
|
const cliOpts = getopts(argv, {
|
||||||
alias: {
|
alias: {
|
||||||
env: 'e',
|
env: 'e',
|
||||||
workdir: 'w',
|
workspace: 'w',
|
||||||
help: 'h',
|
help: 'h',
|
||||||
version: 'v'
|
version: 'v'
|
||||||
},
|
},
|
||||||
default: {
|
default: {
|
||||||
workdir: process.cwd(),
|
workspace: process.cwd(),
|
||||||
env: 'production'
|
env: 'production'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -26,14 +26,14 @@ const cliOpts = getopts(argv, {
|
||||||
if (cliOpts.version)
|
if (cliOpts.version)
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|
||||||
const action = cliOpts._[0];
|
const command = cliOpts._[0];
|
||||||
if (!action) {
|
if (!command) {
|
||||||
console.log('Usage:'.gray, '[npx] myvc [-w|--workdir] [-e|--env] [-h|--help] action'.blue);
|
console.log('Usage:'.gray, '[npx] myvc [-w|--workspace] [-e|--env] [-h|--help] command'.blue);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionArgs = {
|
const commandArgs = {
|
||||||
apply: {
|
push: {
|
||||||
alias: {
|
alias: {
|
||||||
force: 'f',
|
force: 'f',
|
||||||
user: 'u'
|
user: 'u'
|
||||||
|
@ -45,8 +45,8 @@ const actionArgs = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const actionOpts = getopts(argv, actionArgs[action]);
|
const commandOpts = getopts(argv, commandArgs[command]);
|
||||||
Object.assign(cliOpts, actionOpts);
|
Object.assign(cliOpts, commandOpts);
|
||||||
|
|
||||||
const opts = {};
|
const opts = {};
|
||||||
for (let opt in cliOpts) {
|
for (let opt in cliOpts) {
|
||||||
|
@ -59,15 +59,15 @@ function parameter(parameter, value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
parameter('Environment:', opts.env);
|
parameter('Environment:', opts.env);
|
||||||
parameter('Workdir:', opts.workdir);
|
parameter('Workspace:', opts.workspace);
|
||||||
parameter('Action:', action);
|
parameter('Command:', command);
|
||||||
|
|
||||||
class MyVC {
|
class MyVC {
|
||||||
async init(opts) {
|
async init(opts) {
|
||||||
// Configuration file
|
// Configuration file
|
||||||
|
|
||||||
const configFile = 'myvc.config.json';
|
const configFile = 'myvc.config.json';
|
||||||
const configPath = path.join(opts.workdir, configFile);
|
const configPath = path.join(opts.workspace, configFile);
|
||||||
if (!await fs.pathExists(configPath))
|
if (!await fs.pathExists(configPath))
|
||||||
throw new Error(`Config file not found: ${configFile}`);
|
throw new Error(`Config file not found: ${configFile}`);
|
||||||
const config = require(configPath);
|
const config = require(configPath);
|
||||||
|
@ -81,7 +81,7 @@ class MyVC {
|
||||||
let iniDir = __dirname;
|
let iniDir = __dirname;
|
||||||
if (opts.env) {
|
if (opts.env) {
|
||||||
iniFile = `db.${opts.env}.ini`;
|
iniFile = `db.${opts.env}.ini`;
|
||||||
iniDir = opts.workdir;
|
iniDir = opts.workspace;
|
||||||
}
|
}
|
||||||
const iniPath = path.join(iniDir, iniFile);
|
const iniPath = path.join(iniDir, iniFile);
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ class MyVC {
|
||||||
|
|
||||||
if (iniConfig.ssl_ca) {
|
if (iniConfig.ssl_ca) {
|
||||||
dbConfig.ssl = {
|
dbConfig.ssl = {
|
||||||
ca: await fs.readFile(`${opts.workdir}/${iniConfig.ssl_ca}`),
|
ca: await fs.readFile(`${opts.workspace}/${iniConfig.ssl_ca}`),
|
||||||
rejectUnauthorized: iniConfig.ssl_verify_server_cert != undefined
|
rejectUnauthorized: iniConfig.ssl_verify_server_cert != undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,52 +114,44 @@ class MyVC {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async structure (opts) {
|
async pull(opts) {
|
||||||
await dockerRun('export-structure.sh',
|
const pull = require('./myvc-pull');
|
||||||
opts.workdir,
|
await pull(
|
||||||
opts.configFile,
|
opts.workspace,
|
||||||
opts.iniFile
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fixtures(opts) {
|
|
||||||
await dockerRun('export-fixtures.sh',
|
|
||||||
opts.workdir,
|
|
||||||
opts.configFile,
|
|
||||||
opts.iniFile
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async routines(opts) {
|
|
||||||
const exportRoutines = require('./export-routines');
|
|
||||||
await exportRoutines(
|
|
||||||
opts.workdir,
|
|
||||||
opts.schemas,
|
opts.schemas,
|
||||||
opts.dbConfig
|
opts.dbConfig
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async apply(opts) {
|
async push(opts) {
|
||||||
let args = [];
|
let args = [];
|
||||||
if (opts.force) args.push('-f');
|
if (opts.force) args.push('-f');
|
||||||
if (opts.user) args.push('-u');
|
if (opts.user) args.push('-u');
|
||||||
if (opts.env) args = args.concat(['-e', opts.env]);
|
if (opts.env) args = args.concat(['-e', opts.env]);
|
||||||
|
|
||||||
await dockerRun('apply-changes.sh',
|
await dockerRun('myvc-push.sh',
|
||||||
opts.workdir,
|
opts.workspace,
|
||||||
...args
|
...args
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async dump (opts) {
|
||||||
|
await dockerRun('myvc-dump.sh',
|
||||||
|
opts.workspace,
|
||||||
|
opts.configFile,
|
||||||
|
opts.iniFile
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async run(opts) {
|
async run(opts) {
|
||||||
const Docker = require('./docker');
|
const Docker = require('./docker');
|
||||||
const container = new Docker(opts.code, opts.workdir);
|
const container = new Docker(opts.code, opts.workspace);
|
||||||
await container.run();
|
await container.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(opts) {
|
async start(opts) {
|
||||||
const Docker = require('./docker');
|
const Docker = require('./docker');
|
||||||
const container = new Docker(opts.code, opts.workdir);
|
const container = new Docker(opts.code, opts.workspace);
|
||||||
await container.start();
|
await container.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,11 +160,11 @@ class MyVC {
|
||||||
try {
|
try {
|
||||||
const myvc = new MyVC();
|
const myvc = new MyVC();
|
||||||
|
|
||||||
if (myvc[action]) {
|
if (myvc[command]) {
|
||||||
await myvc.init(opts);
|
await myvc.init(opts);
|
||||||
await myvc[action](opts);
|
await myvc[command](opts);
|
||||||
} else
|
} else
|
||||||
throw new Error (`Unknown action '${action}'`);
|
throw new Error (`Unknown command '${command}'`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.name == 'Error')
|
if (err.name == 'Error')
|
||||||
console.error('Error:'.gray, err.message.red);
|
console.error('Error:'.gray, err.message.red);
|
||||||
|
|
|
@ -3,15 +3,25 @@ set -e
|
||||||
|
|
||||||
CONFIG_FILE=$1
|
CONFIG_FILE=$1
|
||||||
INI_FILE=$2
|
INI_FILE=$2
|
||||||
DUMP_FILE="dump/fixtures.sql"
|
DUMP_FILE=".dump.sql"
|
||||||
|
|
||||||
echo "SELECT 1;" | mysql --defaults-file="$INI_FILE" >> /dev/null
|
echo "SELECT 1;" | mysql --defaults-file="$INI_FILE" >> /dev/null
|
||||||
echo "" > "$DUMP_FILE"
|
SCHEMAS=( $(jq -r ".schemas[]" "$CONFIG_FILE") )
|
||||||
|
|
||||||
|
mysqldump \
|
||||||
|
--defaults-file="$INI_FILE" \
|
||||||
|
--default-character-set=utf8 \
|
||||||
|
--no-data \
|
||||||
|
--comments \
|
||||||
|
--triggers --routines --events \
|
||||||
|
--databases \
|
||||||
|
${SCHEMAS[@]} \
|
||||||
|
| sed 's/ AUTO_INCREMENT=[0-9]* //g' \
|
||||||
|
> "$DUMP_FILE"
|
||||||
|
|
||||||
for SCHEMA in $(jq -r ".fixtures | keys[]" "$CONFIG_FILE"); do
|
for SCHEMA in $(jq -r ".fixtures | keys[]" "$CONFIG_FILE"); do
|
||||||
TABLES=( $(jq -r ".fixtures.$SCHEMA[]" "$CONFIG_FILE") )
|
TABLES=( $(jq -r ".fixtures.$SCHEMA[]" "$CONFIG_FILE") )
|
||||||
|
|
||||||
echo " -> $SCHEMA"
|
|
||||||
echo "USE \`$SCHEMA\`;" >> "$DUMP_FILE"
|
echo "USE \`$SCHEMA\`;" >> "$DUMP_FILE"
|
||||||
mysqldump \
|
mysqldump \
|
||||||
--defaults-file="$INI_FILE" \
|
--defaults-file="$INI_FILE" \
|
|
@ -48,7 +48,7 @@ const exporters = [
|
||||||
|
|
||||||
// Exports objects for all schemas
|
// Exports objects for all schemas
|
||||||
|
|
||||||
module.exports = async function main(workdir, schemas, dbConf) {
|
module.exports = async function main(workspace, schemas, dbConf) {
|
||||||
const conn = await mysql.createConnection(dbConf);
|
const conn = await mysql.createConnection(dbConf);
|
||||||
conn.queryFromFile = function(file, params) {
|
conn.queryFromFile = function(file, params) {
|
||||||
return this.execute(
|
return this.execute(
|
||||||
|
@ -58,7 +58,7 @@ module.exports = async function main(workdir, schemas, dbConf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const exportDir = `${workdir}/routines`;
|
const exportDir = `${workspace}/routines`;
|
||||||
if (fs.existsSync(exportDir))
|
if (fs.existsSync(exportDir))
|
||||||
fs.removeSync(exportDir, {recursive: true});
|
fs.removeSync(exportDir, {recursive: true});
|
||||||
fs.mkdirSync(exportDir);
|
fs.mkdirSync(exportDir);
|
|
@ -1,10 +1,13 @@
|
||||||
{
|
{
|
||||||
"name": "myvc",
|
"name": "myvc",
|
||||||
"version": "1.0.7",
|
"version": "1.0.9",
|
||||||
"author": "Verdnatura Levante SL",
|
"author": "Verdnatura Levante SL",
|
||||||
"description": "MySQL Version Control",
|
"description": "MySQL Version Control",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"bin": "myvc.js",
|
"bin": {
|
||||||
|
"myvc": "myvc.js",
|
||||||
|
"myvc-push": "myvc-push.sh"
|
||||||
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/verdnatura/myvc.git"
|
"url": "https://github.com/verdnatura/myvc.git"
|
||||||
|
|
Loading…
Reference in New Issue