diff --git a/containers/postgres.ts b/containers/postgres.ts index 47e4941..2195413 100644 --- a/containers/postgres.ts +++ b/containers/postgres.ts @@ -3,8 +3,27 @@ import getPort from "port"; import psql, { type Sql } from "postgres"; import type { Container } from "../docker/libraries/container.ts"; -import { docker } from "../docker/mod.ts"; +import { docker } from "../mod.ts"; +/** + * @module + * + * Provides the ability to quickly run a postgres image in a docker instance. + * + * @example + * ```ts + * import { PostgresTestContainer } from "@valkyr/testcontainers/postgres"; + * + * const container = await PostgresTestContainer.start("postgres:16"); + * + * await container.create("db"); + * await container.client("db")`SELECT 1`; + * + * console.log(container.url("db")); // => postgres://postgres:postgres@127.0.0.1:5432/db + * + * await container.stop(); + * ``` + */ export class PostgresTestContainer { private constructor( readonly container: Container, diff --git a/deno.json b/deno.json index fa21897..7207619 100644 --- a/deno.json +++ b/deno.json @@ -1,7 +1,8 @@ { "name": "@valkyr/testcontainers", - "version": "1.0.1", + "version": "1.0.2", "exports": { + ".": "./mod.ts", "./postgres": "./containers/postgres.ts" }, "imports": { @@ -24,6 +25,15 @@ "fmt": { "lineWidth": 120 }, + "publish": { + "exclude": [ + ".eslint", + ".github", + ".vscode", + ".gitignore", + "tests" + ] + }, "tasks": { "lint": "deno lint && npx eslint -c .eslint/eslint.config.mjs .", "test": "export ENVIRONMENT=testing && deno test --allow-all --unstable-ffi" diff --git a/docker/libraries/docker.ts b/docker/libraries/docker.ts index baed243..5008b90 100644 --- a/docker/libraries/docker.ts +++ b/docker/libraries/docker.ts @@ -3,6 +3,20 @@ import { Container } from "./container.ts"; import { Image } from "./image.ts"; import { modem } from "./modem.ts"; +/** + * @module + * + * A simple wrapper for pulling a docker image, and creating docker containers. + * + * @example + * ```ts + * import { docker } from "@valkyr/testcontainers"; + * + * await docker.pullImage("docker:image"); + * + * const container = await docker.createContainer({ Image: "docker:image" }); + * ``` + */ export class Docker { /** * Create a new docker container. @@ -12,7 +26,10 @@ export class Docker { * @params config - The configuration for the container. * @params query - Query parameters. */ - async createContainer(config: Partial, query: Partial<{ name: string; platform: string }> = {}) { + async createContainer( + config: Partial, + query: Partial<{ name: string; platform: string }> = {}, + ): Promise { const { Id, Warnings } = await modem.post<{ Id: string; Warnings: string[] }>({ path: "/containers/create", query, @@ -26,7 +43,7 @@ export class Docker { * * @param image - The image to pull. */ - async pullImage(image: string) { + async pullImage(image: string): Promise { await new Image().create({ fromImage: image }); } } diff --git a/docker/libraries/exec.ts b/docker/libraries/exec.ts index 4034a13..e92f36e 100644 --- a/docker/libraries/exec.ts +++ b/docker/libraries/exec.ts @@ -12,7 +12,7 @@ export class Exec { * * @param body - Request body schema. */ - async start(body: Partial = {}) { + async start(body: Partial = {}): Promise { await modem.post({ path: `/exec/${this.id}/start`, body }); await this.#endSignal(); } @@ -20,7 +20,7 @@ export class Exec { /** * Return low-level information about the exec instance. */ - async inspect() { + async inspect(): Promise { return modem.get({ path: `/exec/${this.id}/json` }); } @@ -37,7 +37,7 @@ export class Exec { * [TODO] Introduce a timeout signal in case we want to add a treshold to the * running time. */ - async #endSignal() { + async #endSignal(): Promise { while (true) { const info = await this.inspect(); if (info.Running === false) { diff --git a/docker/libraries/modem.ts b/docker/libraries/modem.ts index bbc22eb..3306150 100644 --- a/docker/libraries/modem.ts +++ b/docker/libraries/modem.ts @@ -1,7 +1,10 @@ import { Client, type Response } from "../../http/mod.ts"; class Modem { - constructor(readonly options: Deno.ConnectOptions | Deno.UnixConnectOptions, readonly client = new Client(options)) {} + constructor( + readonly options: Deno.ConnectOptions | Deno.UnixConnectOptions, + readonly client: Client = new Client(options), + ) {} /** * Send a `POST` request to the Docker API. @@ -59,7 +62,7 @@ class Modem { } } -export const modem = new Modem({ +export const modem: Modem = new Modem({ path: "/var/run/docker.sock", transport: "unix", }); diff --git a/docker/mod.ts b/docker/mod.ts deleted file mode 100644 index 3aacbf3..0000000 --- a/docker/mod.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Docker } from "./libraries/docker.ts"; - -export const docker = new Docker(); diff --git a/http/libraries/client.ts b/http/libraries/client.ts index e44eb46..2bb39e0 100644 --- a/http/libraries/client.ts +++ b/http/libraries/client.ts @@ -11,7 +11,7 @@ export class Client { * closed when accessing the .stream on the response. Otherwise a manual .close must * be executed on the response to ensure that the connection is cleaned up. */ - get connection() { + get connection(): Promise | Promise { if ("path" in this.options) { return Deno.connect(this.options); } diff --git a/mod.ts b/mod.ts new file mode 100644 index 0000000..bb74a76 --- /dev/null +++ b/mod.ts @@ -0,0 +1,9 @@ +import { Docker } from "./docker/libraries/docker.ts"; + +export type { Container } from "./docker/libraries/container.ts"; +export type { Docker } from "./docker/libraries/docker.ts"; +export type { Exec } from "./docker/libraries/exec.ts"; +export type { Image } from "./docker/libraries/image.ts"; +export { modem } from "./docker/libraries/modem.ts"; + +export const docker: Docker = new Docker();