Skip to content

Commit

Permalink
kivik deploy local and other minor changes (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sascha Adler authored Apr 8, 2021
1 parent 21eaea0 commit c5bca03
Show file tree
Hide file tree
Showing 13 changed files with 182 additions and 107 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [2.0.0-alpha.8] - 2021-04-08

- `kivik deploy local` deploys to a running Kivik instance, unless a deployment with key `local` exists in the RC file.
- `kivik start` does not deploy by default.
- RC file deployments can set a `fixtures` flag to determine if deployments should also deploy fixtures. This is false by default.
- `kivik deploy` checks this flag (as well as the `local.fixtures` for `kivik deploy local`) when deploying.
- `instance.deployDb(db: string, suffix?: string)` lets test suites deploy one database at a time.

## [2.0.0-alpha.7] - 2021-04-08

- New CLI invocations: `kivik start`, `kivik watch`, `kivik stop`. `kivik inspect`, `kivik dev` and `kivik instance` are aliases of `kivik watch`, and nothing particularly new happens if you keep using those like you used to. `kivik start` and `kivik stop` start and stop the Kivik instance in the background.
Expand Down Expand Up @@ -110,6 +118,7 @@
- Multiple design document support
- View (map/reduce) and update function support within design documents

[2.0.0-alpha.8]: https://github.com/crkn-rcdr/kivik/releases/tag/v2.0.0-alpha.8
[2.0.0-alpha.7]: https://github.com/crkn-rcdr/kivik/releases/tag/v2.0.0-alpha.7
[2.0.0-alpha.6]: https://github.com/crkn-rcdr/kivik/releases/tag/v2.0.0-alpha.6
[2.0.0-alpha.5]: https://github.com/crkn-rcdr/kivik/releases/tag/v2.0.0-alpha.5
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ export interface Deployment {
};
/** Suffix to append to the end of each database name. Default: `undefined` */
suffix?: string;
/** Whether or not to deploy fixtures along with the design documents. */
fixtures?: boolean;
/** List of databases to deploy. By default, all databases are deployed. */
dbs?: string[];
}

/** Configuration for Kivik instances. */
Expand Down Expand Up @@ -181,10 +185,12 @@ $ kivik deploy production
import { createKivik } from "kivik";

const kivik = await createKivik("path/to/dir", "deploy");
await kivik.deployTo("production");
await kivik.deploy("production");
await kivik.close();
```

If you deploy to `local`, you will deploy to a running Kivik instance (see below), unless you have a deployment with key `local` in your RC file.

### Instance

```shell
Expand Down Expand Up @@ -235,7 +241,7 @@ test("Your fixture looks good", async (t) => {
});
```

When a Kivik instance is running, Kivik saves its container's name to `$DIR/.kivik.tmp`. If this file is altered or deleted, Kivik won't be able to find the running instance it might be referring to. The file is deleted when a Kivik instance is stopped.
When a Kivik instance is running, Kivik saves its container's name to `$DIR/.kivik.tmp`. If this file is altered or deleted, Kivik won't be able to find the running instance it might be referring to. The file is deleted when a Kivik instance is stopped. Only one Kivik instance can run at a time.

## Testing Kivik

Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kivik",
"version": "2.0.0-alpha.7",
"version": "2.0.0-alpha.8",
"description": "An opinionated library and command-line utility for configuration CouchDB endpoints, databases, and design documents",
"keywords": [
"couchdb"
Expand All @@ -19,9 +19,12 @@
}
],
"license": "Unlicense",
"main": "./dist/index.js",
"files": [
"dist/**"
],
"main": "dist/index.js",
"bin": {
"kivik": "./dist/bin.js"
"kivik": "dist/bin.js"
},
"engines": {
"node": ">=12.0.0"
Expand Down
43 changes: 26 additions & 17 deletions src/cli/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,36 @@ export default (unloggedContext: UnloggedContext) => {
command: "deploy <deployment>",
describe: "Deploys design documents to a remote database",
builder: (yargs: yargs.Argv<CommonArgv>) =>
yargs
.positional("deployment", {
type: "string",
describe: "Key of a deployment object in your kivikrc file",
})
.check((argv: DeployArgv): boolean => {
const key = argv.deployment as string;
const deployment = unloggedContext.deployments[key];

if (!deployment)
throw new Error(`No deployment in kivikrc for key ${key}`);

return true;
}),
yargs.positional("deployment", {
type: "string",
describe: "Key of a deployment object in your kivikrc file",
}),
handler: async (argv: DeployArgv) => {
const context = unloggedContext.withArgv(argv);
const kivik = await createKivik(context, "deploy");

await kivik.deployTo(argv.deployment as string);
let deployment;
try {
deployment = await context.getDeployment(argv.deployment || "");
} catch (error) {
context.log("error", error.message);
process.exit(1);
}

let kivik;
try {
kivik = await createKivik(
context,
deployment.fixtures ? "instance" : "deploy"
);
await kivik.deploy(deployment);
await kivik.close();
process.exit(0);
} catch (error) {
context.log("error", `Error deploying: ${error.message}`);
process.exitCode = 1;
}

await kivik.close();
if (kivik) await kivik.close();
},
};
};
3 changes: 1 addition & 2 deletions src/cli/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ export default (unloggedContext: UnloggedContext) => {
const context = unloggedContext.withArgv(argv);

try {
const instance = await createInstance(context, false);
await instance.deploy();
const instance = await createInstance(context, { attach: false });
await instance.detach();
instance.announce();
} catch (error) {
Expand Down
1 change: 1 addition & 0 deletions src/cli/stop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default (unloggedContext: UnloggedContext) => {
try {
const instance = await getInstance(context);
await instance.stop();
context.log("success", "Kivik instance stopped.");
} catch (error) {
context.log(
"error",
Expand Down
39 changes: 37 additions & 2 deletions src/context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import { sync as findUp } from "find-up";

import { CommonArgv } from "../cli";
import { createLogger, LogLevel } from "./logger";
import { normalizeRc, NormalizedRc } from "./rc";
import { normalizeRc, NormalizedRc, Deployment, NanoDeployment } from "./rc";
import { get as remoteNano } from "@crkn-rcdr/nano";
import { getInstance } from "../instance";

export { logLevels, LogLevel } from "./logger";

export {
Deployment,
NanoDeployment,
InstanceConfig,
normalizeInstanceConfig,
NormalizedInstanceConfig,
Expand All @@ -24,6 +27,10 @@ export type UnloggedContext = NormalizedRc & {

export type Context = Omit<UnloggedContext, "withArgv"> & {
readonly log: (level: LogLevel, message: string) => void;
readonly getDeployment: (
key: string,
suffix?: string
) => Promise<NanoDeployment>;
readonly withDatabase: (db: string) => DatabaseContext;
};

Expand All @@ -42,16 +49,44 @@ export const createContext = (directory: string): UnloggedContext => {
return {
directory,
...rc,
withArgv: function (argv: CommonArgv): Context {
withArgv: function (argv: CommonArgv) {
// https://no-color.org
if (process.env.hasOwnProperty("NO_COLOR")) argv.color = false;

const logger = createLogger(argv);
if (!confPath)
logger.log(
"warn",
"No kivikrc file detected. Proceeding with defaults."
);
logger.log("info", "Logger initialized.");

return {
...this,
log: (level: LogLevel, message: string) => logger.log(level, message),
getDeployment: async function (key: string, suffix?: string) {
if (key in this.deployments) {
const deployment = this.deployments[key] as Deployment;
return {
nano: remoteNano(deployment.url, deployment.auth),
suffix: suffix || deployment.suffix,
fixtures: !!deployment.fixtures,
dbs: deployment.dbs || null,
};
} else if (key === "local") {
const instance = await getInstance(this);
return {
nano: instance.nano,
suffix,
fixtures: this.local.fixtures,
dbs: null,
};
} else {
throw new Error(
`Your kivikrc file does not have a deployment with key '${key}'`
);
}
},
withDatabase: function (db: string): DatabaseContext {
return {
...this,
Expand Down
13 changes: 13 additions & 0 deletions src/context/rc.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ServerScope } from "nano";

/** Kivik RC file configuration. */
export interface Rc {
/**
Expand Down Expand Up @@ -31,8 +33,19 @@ export interface Deployment {
};
/** Suffix to append to the end of each database name. Default: `undefined` */
suffix?: string;
/** Whether or not to deploy fixtures along with the design documents Default: `false`. */
fixtures?: boolean;
/** List of databases to deploy. By default, all databases are deployed. */
dbs?: string[];
}

export type NanoDeployment = {
nano: ServerScope;
suffix?: string;
fixtures: boolean;
dbs: string[] | null;
};

/** Configuration for Kivik instances. */
export interface InstanceConfig {
/** Deploy fixtures when running `kivik dev`. Default: `true` */
Expand Down
9 changes: 3 additions & 6 deletions src/instance/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { localhost as localNano } from "@crkn-rcdr/nano";
import { ServerScope } from "nano";
import pRetry from "p-retry";

import { Context, NormalizedInstanceConfig } from "../context";
import { Context } from "../context";

const tempfile = (directory: string) => pathJoin(directory, ".kivik.tmp");
const getNano = (port: number, context: Context) =>
Expand Down Expand Up @@ -50,11 +50,8 @@ export const getContainer = async (context: Context) => {
}
};

export const createContainer = async (
context: Context,
instanceConfig: NormalizedInstanceConfig
): Promise<Container> => {
const { port: desiredPort, image, user, password } = instanceConfig;
export const createContainer = async (context: Context): Promise<Container> => {
const { port: desiredPort, image, user, password } = context.local;

const port = await getPort({ port: desiredPort });

Expand Down
4 changes: 1 addition & 3 deletions src/instance/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import anyTest, { TestInterface } from "ava";

import { createInstance, Instance } from ".";
import { directory } from "../example";
import { DatabaseHandler } from "../kivik";

interface LocalContext {
instance: Instance;
Expand All @@ -20,8 +19,7 @@ test("Can survive multiple deploys", async (t) => {
);
await Promise.all(
suffixes.map(async (suffix) => {
const handlers = await t.context.instance.deploy(suffix);
const testdb = handlers.get("testdb") as DatabaseHandler;
const testdb = await t.context.instance.deployDb("testdb", suffix);
const pickwick = await testdb.get("pickwick-papers");
t.is(pickwick["_id"], "pickwick-papers");
})
Expand Down
Loading

0 comments on commit c5bca03

Please sign in to comment.