Skip to content

Commit

Permalink
feat: Command hooks: global and per site
Browse files Browse the repository at this point in the history
Plus workarounds for non-required config sections
  • Loading branch information
MurzNN committed Feb 22, 2022
1 parent 3b27dd9 commit f3d966b
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 28 deletions.
11 changes: 11 additions & 0 deletions sites-sync.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ databases:
# different usernames per site
dump: --no-owner

# Here you can define custom hooks to execute before and after command
# commandsHooks:
# pull:
# before: scripts/clear-cache
# after: scripts/rebuild-cache

# List of storage locations to sync in format: "name: path"
# Path can be relative or absolute.
directories:
Expand All @@ -67,6 +73,11 @@ sites:
stage:
execCommand: kubectl exec -n mycoolsite-staging -i deployment/mycoolsite
terminalCommand: kubectl exec -n mycoolsite-staging -i -t deployment/mycoolsite
# Here you can override custom hooks per site
# commandsHooks:
# pull:
# before: scripts/clear-cache; scritps/kube-upstream-config.sh
# after: scripts/rebuild-cache

live:
execCommand: kubectl exec -n mycoolsite-prod -i deployment/mycoolsite
Expand Down
43 changes: 31 additions & 12 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ function getCommand(nameOrAlias: string): string {
return nameOrAlias;
}

function getCommandHook(
command: string,
hookType: "before" | "after"
): string | undefined {
return (
config.siteCurrent?.commandsHooks?.[command]?.[hookType] ??
config.commandsHooks?.[command]?.[hookType] ??
undefined
);
}

const myYargs = yargs(process.argv.slice(2))
.scriptName("sites-sync")
.usage("Usage: $0 <command> [options]")
Expand All @@ -66,10 +77,12 @@ const myYargs = yargs(process.argv.slice(2))
.middleware(function (argv) {
if (!argv._[0]) return;
const command = getCommand(argv._[0] as string);
if (command && config.commandHooks?.[command]?.before) {
const cmd = config.commandHooks?.[command]?.before as string;
console.log(`Executing "before" hook for command "${command}": ${cmd}`);
execSync(cmd, { stdio: "inherit" });
const commandHookBefore = getCommandHook(command, "before");
if (commandHookBefore) {
console.log(
`Executing "before" hook for command "${command}": ${commandHookBefore}`
);
execSync(commandHookBefore, { stdio: "inherit" });
console.log(`"before" hook executing finished.`);
}
})
Expand Down Expand Up @@ -149,7 +162,8 @@ const myYargs = yargs(process.argv.slice(2))
"Dump database to stdout.",
{},
async (argv) => {
const dbId = (argv.dbId as string) ?? Object.keys(config.databases)[0];
const dbId =
(argv.dbId as string) ?? Object.keys(config.databases ?? {})[0];
doDatabaseDump(dbId);
}
)
Expand All @@ -158,7 +172,8 @@ const myYargs = yargs(process.argv.slice(2))
"Execute db query from stdin.",
{},
async (argv) => {
const dbId = (argv.dbId as string) ?? Object.keys(config.databases)[0];
const dbId =
(argv.dbId as string) ?? Object.keys(config.databases ?? {})[0];
doDatabaseQuery(dbId);
}
)
Expand All @@ -167,7 +182,8 @@ const myYargs = yargs(process.argv.slice(2))
"Clear current database.",
{},
async (argv) => {
const dbId = (argv.dbId as string) ?? Object.keys(config.databases)[0];
const dbId =
(argv.dbId as string) ?? Object.keys(config.databases ?? {})[0];
doDatabaseClear(dbId);
}
)
Expand All @@ -176,7 +192,8 @@ const myYargs = yargs(process.argv.slice(2))
"Import database dump from stdin.",
{},
async (argv) => {
const dbId = (argv.dbId as string) ?? Object.keys(config.databases)[0];
const dbId =
(argv.dbId as string) ?? Object.keys(config.databases ?? {})[0];
doDatabaseClear(dbId);
}
)
Expand Down Expand Up @@ -251,10 +268,12 @@ if (argv._.length == 0) {
myYargs.showHelp();
} else {
const command = getCommand(argv._[0] as string);
if (command && config.commandHooks?.[command]?.after) {
const cmd = config.commandHooks?.[command]?.after as string;
console.log(`Executing "after" hook for command "${command}": ${cmd}`);
execSync(cmd, { stdio: "inherit" });
const commandHookAfter = getCommandHook(command, "after");
if (commandHookAfter) {
console.log(
`Executing "after" hook for command "${command}": ${commandHookAfter}`
);
execSync(commandHookAfter, { stdio: "inherit" });
console.log(`"after" hook executing finished.`);
}
}
14 changes: 7 additions & 7 deletions src/lib/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@ import {
import { dbAdapters } from "./dbAdapters.js";

export function doDatabaseDump(dbId: string) {
if (!config.databases[dbId]) {
if (!config.databases?.[dbId]) {
throw Error(`Database with id ${dbId} not found in config`);
}
dbAdapters[dbId].dump();
}

export function doDatabaseQuery(dbId: string, query: string | null = null) {
if (!config.databases[dbId]) {
if (!config.databases?.[dbId]) {
throw Error(`Database with id ${dbId} not found in config`);
}
dbAdapters[dbId].query(query);
}
export function doDatabaseClear(dbId: string) {
destructiveOperationCheck();
if (!config.databases[dbId]) {
if (!config.databases?.[dbId]) {
throw Error(`Database with id ${dbId} not found in config`);
}
dbAdapters[dbId].clear();
Expand Down Expand Up @@ -116,7 +116,7 @@ export function doDatabasesBackup(backupDirectory: DirectoryPath): void {
}

export function doDatabaseBackup(dbId: string, file: FilePath): void {
if (!config.databases[dbId]) {
if (!config.databases?.[dbId]) {
throw Error(`Database with id ${dbId} not found in config`);
}
dbAdapters[dbId].dumpToFile(file);
Expand All @@ -132,7 +132,7 @@ export function doDatabasesRestore(backupDirectory: DirectoryPath): void {

export function doDatabaseRestore(dbId: string, file: FilePath): void {
destructiveOperationCheck();
if (!config.databases[dbId]) {
if (!config.databases?.[dbId]) {
throw Error(`Database with id ${dbId} not found in config`);
}
dbAdapters[dbId].restoreFromFile(file);
Expand Down Expand Up @@ -170,7 +170,7 @@ export function doDirectoryBackup(
directoryId: string,
backupDirectory: DirectoryPath
): void {
const path = config.directories[directoryId] as DirectoryPath;
const path = config.directories?.[directoryId] as DirectoryPath;
const file = backupFilePath("directory", directoryId, backupDirectory);
console.log(
`Backing up directory "${directoryId}" to archive file "${file}" ...`
Expand All @@ -191,7 +191,7 @@ export function doDirectoryRestore(
backupDirectory: DirectoryPath
): void {
destructiveOperationCheck();
const path = config.directories[directoryId] as DirectoryPath;
const path = config.directories?.[directoryId] as DirectoryPath;
const file = backupFilePath("directory", directoryId, backupDirectory);
console.log(
`Restoring directory "${directoryId}" from archive file "${file}" ...`
Expand Down
2 changes: 1 addition & 1 deletion src/lib/dbAdapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { dbAdapterFactory } from "./dbAdapterFactory.js";
export const dbAdapters: any = {};

for (const dbId in config.databases) {
const dbConnection = config.databases[dbId];
const dbConnection = config.databases?.[dbId];
if (!dbConnection.uri) {
throw Error(`Database ${dbId} have empty "uri"`);
}
Expand Down
16 changes: 14 additions & 2 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ export const getTmpFilename = function () {
};

export function prepareBackupDirectory(): DirectoryPath {
let directoryName = config.backup.nameFormat;
if (directoryName == "/" || directoryName == "") {
if (!config.backup) {
throw Error(`Backup configuration is not defined`);
}
let directoryName = config.backup?.nameFormat;
if (directoryName == "/" || !directoryName) {
throw "Backup directory target is empty or pointing to root!";
}
const matches = /{%TIME:(?<time>[^%]+)%}/.exec(directoryName);
Expand All @@ -46,6 +49,9 @@ export function prepareBackupDirectory(): DirectoryPath {
}

export function getBackupDirectory(backupName?: string): DirectoryPath {
if (!config.backup) {
throw Error(`Backup configuration is not defined`);
}
if (!backupName) {
backupName = execSync(`ls -1 -t ${config.backup.directory} | head -n 1`)
.toString()
Expand All @@ -55,6 +61,9 @@ export function getBackupDirectory(backupName?: string): DirectoryPath {
}

export function backupDirectoryCleanup(): void {
if (!config.backup) {
throw Error(`Backup configuration is not defined`);
}
const BackupDirectory = prepareDirectoryPath(config.backup.directory);
if ((config.backup.keepAmount ?? 0) < 1) {
return;
Expand All @@ -76,6 +85,9 @@ export function backupDirectoryCleanup(): void {
}

export function backupDirectoryDeleteAll(): void {
if (!config.backup) {
throw Error(`Backup configuration is not defined`);
}
const BackupDirectory = prepareDirectoryPath(config.backup.directory);
if ((config.backup.keepAmount ?? 0) < 1) {
return;
Expand Down
15 changes: 9 additions & 6 deletions src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export type SitesSyncConfigSite = {
quoteCommands?: boolean;
databasesOverride?: SitesSyncConfigDbConnection;
disableDestructiveOperations?: boolean;
commandsHooks?: {
[key: string]: SitesSyncConfigHook;
};
};

export type SitesSyncConfigDbConnection = {
Expand All @@ -29,24 +32,24 @@ export type SitesSyncConfigHook = {

export type SitesSyncConfig = {
siteId: string;
siteUpstreamId: string;
siteUpstreamId?: string;

backup: {
backup?: {
directory: string;
nameFormat: string;
keepAmount?: number;
};
tempDirectory: string;
tempDirectory?: string;

databases: {
databases?: {
[key: string]: SitesSyncConfigDbConnection;
};

directories: {
directories?: {
[key: string]: string;
};

commandHooks: {
commandsHooks?: {
[key: string]: SitesSyncConfigHook;
};

Expand Down

0 comments on commit f3d966b

Please sign in to comment.