Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
.github
.idea
dist
lib/types
!lib/types/FileInfo.ts
node_modules
out
junit.xml
102 changes: 99 additions & 3 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["import", "typescript", "unicorn"],
"plugins": [
"import",
"unicorn",
"node",
"oxc",
"eslint",
"promise",
"vitest",
"jsdoc"
],
"env": {
"node": true,
"es6": true
},
"globals": {},
"settings": {},
"categories": {
"correctness": "error",
"perf": "error",
"suspicious": "warn"
},
"rules": {
"eqeqeq": "error",
"import/no-cycle": "error",
Expand All @@ -18,7 +32,89 @@
"varsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_"
}
]
],
"no-await-in-loop": "off",
"jsdoc/check-tag-names": [
"warn",
{
"typed": true,
"enableFixer": false
}
],
"jsdoc/require-yields": "off"
},
"overrides": []
"overrides": [
{
"files": ["*.ts"],
"plugins": ["typescript"],
"rules": {
"typescript/no-floating-promises": [
"error",
{
"ignoreVoid": true,
"ignoreIIFE": true
}
],
"typescript/no-misused-promises": [
"error",
{
"checksVoidReturn": false,
"checksConditionals": true
}
],
"typescript/await-thenable": "error",
"typescript/no-array-delete": "error",
"typescript/no-base-to-string": "error",
"typescript/no-confusing-void-expression": "error",
"typescript/no-duplicate-type-constituents": "error",
"typescript/no-for-in-array": "error",
"typescript/no-implied-eval": "error",
"typescript/no-meaningless-void-operator": "error",
"typescript/no-misused-spread": "error",
"typescript/no-mixed-enums": "error",
"typescript/no-redundant-type-constituents": "error",
"typescript/no-unnecessary-boolean-literal-compare": "error",
"typescript/no-unnecessary-template-expression": "error",
"typescript/no-unnecessary-type-arguments": "error",
"typescript/no-unnecessary-type-assertion": "off",
"typescript/no-extraneous-class": "off",
"typescript/no-unsafe-type-assertion": "off",
"typescript/no-unsafe-enum-comparison": "error",
"typescript/no-unsafe-return": "error",
"typescript/no-unsafe-unary-minus": "error",
"typescript/non-nullable-type-assertion-style": "error",
"typescript/only-throw-error": "error",
"typescript/prefer-promise-reject-errors": "error",
"typescript/prefer-reduce-type-parameter": "error",
"typescript/prefer-return-this-type": "error",
"typescript/related-getter-setter-pairs": "error",
"typescript/require-array-sort-compare": "error",
"typescript/require-await": "error",
"typescript/restrict-plus-operands": "error",
"typescript/restrict-template-expressions": "error",
"typescript/return-await": ["error", "always"],
"typescript/switch-exhaustiveness-check": "error",
"typescript/unbound-method": "error",
"typescript/use-unknown-in-catch-callback-variable": "error"
}
},
// Disable errors with `any | null` types
{
"files": [
"lib/types/ContainerStatsResponse.ts",
"lib/types/SystemVersionComponentsInner.ts"
],
"plugins": ["typescript"],
"rules": {
"typescript/no-redundant-type-constituents": "off"
}
},
// Disable errors with `@` character used within jsdoc description
{
"files": ["lib/types/ExecConfig.ts", "lib/docker-client.ts"],
"rules": {
"check-tag-names": "off"
}
}
]
}
72 changes: 39 additions & 33 deletions lib/docker-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { createConnection } from 'node:net';
import { promises as fsPromises } from 'node:fs';
import { join } from 'node:path';
import { homedir } from 'node:os';
import type { Agent, Response } from 'undici';
import type { Agent } from 'undici';
import type { SecureContextOptions } from 'node:tls';
import { connect as tlsConnect } from 'node:tls';
import type { AuthConfig, BuildInfo, Platform } from './types/index.js';
import type { AuthConfig, Platform } from './types/index.js';
import * as types from './types/index.js';
import {
APPLICATION_JSON,
Expand Down Expand Up @@ -66,6 +66,7 @@ export class DockerClient {
} catch (error) {
throw new Error(
`Failed to create Docker client for ${dockerHost}: ${getErrorMessage(error)}`,
{ cause: error },
);
}
} else if (dockerHost.startsWith('tcp:')) {
Expand Down Expand Up @@ -101,6 +102,7 @@ export class DockerClient {
} catch (error) {
throw new Error(
`Failed to create Docker client for ${dockerHost}: ${getErrorMessage(error)}`,
{ cause: error },
);
}
} else if (dockerHost.startsWith('ssh:')) {
Expand All @@ -112,6 +114,7 @@ export class DockerClient {
} catch (error) {
throw new Error(
`Failed to create SSH Docker client for ${dockerHost}: ${getErrorMessage(error)}`,
{ cause: error },
);
}
} else {
Expand Down Expand Up @@ -179,7 +182,7 @@ export class DockerClient {
} catch {
// TLS directory doesn't exist, certificates remain undefined
}
return DockerClient.fromDockerHost(
return await DockerClient.fromDockerHost(
dockerHost,
certificates,
userAgent,
Expand All @@ -201,6 +204,7 @@ export class DockerClient {
if (isFileNotFoundError(error)) {
throw new Error(
`Docker contexts directory not found: ${contextsDir}`,
{ cause: error },
);
}
throw error;
Expand Down Expand Up @@ -237,14 +241,14 @@ export class DockerClient {

if (config.currentContext) {
// Use the specified current context
return DockerClient.fromDockerContext(
return await DockerClient.fromDockerContext(
config.currentContext,
userAgent,
headers,
);
} else {
// No current context specified, use default
return DockerClient.fromDockerHost(
return await DockerClient.fromDockerHost(
'unix:/var/run/docker.sock',
undefined,
userAgent,
Expand All @@ -258,6 +262,7 @@ export class DockerClient {
} else if (error instanceof SyntaxError) {
throw new Error(
`Invalid JSON in Docker config file: ${configPath}`,
{ cause: error },
);
}
throw error;
Expand Down Expand Up @@ -332,7 +337,7 @@ export class DockerClient {
const response = await this.api.head('/_ping', {
accept: 'text/plain',
});
return response.headers.get('api-version') as string;
return response.headers.get('api-version')!;
}

/**
Expand Down Expand Up @@ -1039,33 +1044,34 @@ export class DockerClient {
* Build an image
*
* @param buildContext A tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz.
* @param dockerfile Path within the build context to the `Dockerfile`. This is ignored if `remote` is specified and points to an external `Dockerfile`.
* @param t A name and optional tag to apply to the image in the `name:tag` format. If you omit the tag the default `latest` value is assumed. You can provide several `t` parameters.
* @param extrahosts Extra hosts to add to /etc/hosts
* @param remote A Git repository URI or HTTP/HTTPS context URI. If the URI points to a single text file, the file's contents are placed into a file called `Dockerfile` and the image is built from that file. If the URI points to a tarball, the file is downloaded by the daemon and the contents therein used as the context for the build. If the URI points to a tarball and the `dockerfile` parameter is also specified, there must be a file with the corresponding path inside the tarball.
* @param q Suppress verbose build output.
* @param nocache Do not use the cache when building the image.
* @param cachefrom JSON array of images used for build cache resolution.
* @param pull Attempt to pull the image even if an older image exists locally.
* @param rm Remove intermediate containers after a successful build.
* @param forcerm Always remove intermediate containers, even upon failure.
* @param memory Set memory limit for build.
* @param memswap Total memory (memory + swap). Set as `-1` to disable swap.
* @param cpushares CPU shares (relative weight).
* @param cpusetcpus CPUs in which to allow execution (e.g., `0-3`, `0,1`).
* @param cpuperiod The length of a CPU period in microseconds.
* @param cpuquota Microseconds of CPU time that the container can get in a CPU period.
* @param buildargs JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. For example, the build arg `FOO=bar` would become `{\"FOO\":\"bar\"}` in JSON. This would result in the query parameter `buildargs={\"FOO\":\"bar\"}`. Note that `{\"FOO\":\"bar\"}` should be URI component encoded. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg)
* @param shmsize Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB.
* @param squash Squash the resulting images layers into a single layer. *(Experimental release only.)*
* @param labels Arbitrary key/value labels to set on the image, as a JSON map of string pairs.
* @param networkmode Sets the networking mode for the run commands during build. Supported standard values are: `bridge`, `host`, `none`, and `container:<name|id>`. Any other value is taken as a custom network\'s name or ID to which this container should connect to.
* @param contentType
* @param xRegistryConfig This is a base64-encoded JSON object with auth configurations for multiple registries that a build may refer to. The key is a registry URL, and the value is an auth configuration object, [as described in the authentication section](#section/Authentication). For example: ``` { \"docker.example.com\": { \"username\": \"janedoe\", \"password\": \"hunter2\" }, \"https://index.docker.io/v1/\": { \"username\": \"mobydock\", \"password\": \"conta1n3rize14\" } } ``` Only the registry domain name (and port if not the default 443) are required. However, for legacy reasons, the Docker Hub registry must be specified with both a `https://` prefix and a `/v1/` suffix even though Docker will prefer to use the v2 registry API.
* @param platform Platform in the format os[/arch[/variant]]
* @param target Target build stage
* @param outputs BuildKit output configuration in the format of a stringified JSON array of objects. Each object must have two top-level properties: `Type` and `Attrs`. The `Type` property must be set to \'moby\'. The `Attrs` property is a map of attributes for the BuildKit output configuration. See https://docs.docker.com/build/exporters/oci-docker/ for more information. Example: ``` [{\"Type\":\"moby\",\"Attrs\":{\"type\":\"image\",\"force-compression\":\"true\",\"compression\":\"zstd\"}}] ```
* @param version Version of the builder backend to use. - `1` is the first generation classic (deprecated) builder in the Docker daemon (default) - `2` is [BuildKit](https://github.com/moby/buildkit)
* @param options
* @param options.dockerfile Path within the build context to the `Dockerfile`. This is ignored if `remote` is specified and points to an external `Dockerfile`.
* @param options.t A name and optional tag to apply to the image in the `name:tag` format. If you omit the tag the default `latest` value is assumed. You can provide several `t` parameters.
* @param options.extrahosts Extra hosts to add to /etc/hosts
* @param options.remote A Git repository URI or HTTP/HTTPS context URI. If the URI points to a single text file, the file's contents are placed into a file called `Dockerfile` and the image is built from that file. If the URI points to a tarball, the file is downloaded by the daemon and the contents therein used as the context for the build. If the URI points to a tarball and the `dockerfile` parameter is also specified, there must be a file with the corresponding path inside the tarball.
* @param options.q Suppress verbose build output.
* @param options.nocache Do not use the cache when building the image.
* @param options.cachefrom JSON array of images used for build cache resolution.
* @param options.pull Attempt to pull the image even if an older image exists locally.
* @param options.rm Remove intermediate containers after a successful build.
* @param options.forcerm Always remove intermediate containers, even upon failure.
* @param options.memory Set memory limit for build.
* @param options.memswap Total memory (memory + swap). Set as `-1` to disable swap.
* @param options.cpushares CPU shares (relative weight).
* @param options.cpusetcpus CPUs in which to allow execution (e.g., `0-3`, `0,1`).
* @param options.cpuperiod The length of a CPU period in microseconds.
* @param options.cpuquota Microseconds of CPU time that the container can get in a CPU period.
* @param options.buildargs JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. For example, the build arg `FOO=bar` would become `{\"FOO\":\"bar\"}` in JSON. This would result in the query parameter `buildargs={\"FOO\":\"bar\"}`. Note that `{\"FOO\":\"bar\"}` should be URI component encoded. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg)
* @param options.shmsize Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB.
* @param options.squash Squash the resulting images layers into a single layer. *(Experimental release only.)*
* @param options.labels Arbitrary key/value labels to set on the image, as a JSON map of string pairs.
* @param options.networkmode Sets the networking mode for the run commands during build. Supported standard values are: `bridge`, `host`, `none`, and `container:<name|id>`. Any other value is taken as a custom network\'s name or ID to which this container should connect to.
* @param options.contentType
* @param options.xRegistryConfig This is a base64-encoded JSON object with auth configurations for multiple registries that a build may refer to. The key is a registry URL, and the value is an auth configuration object, [as described in the authentication section](#section/Authentication). For example: ``` { \"docker.example.com\": { \"username\": \"janedoe\", \"password\": \"hunter2\" }, \"https://index.docker.io/v1/\": { \"username\": \"mobydock\", \"password\": \"conta1n3rize14\" } } ``` Only the registry domain name (and port if not the default 443) are required. However, for legacy reasons, the Docker Hub registry must be specified with both a `https://` prefix and a `/v1/` suffix even though Docker will prefer to use the v2 registry API.
* @param options.platform Platform in the format os[/arch[/variant]]
* @param options.target Target build stage
* @param options.outputs BuildKit output configuration in the format of a stringified JSON array of objects. Each object must have two top-level properties: `Type` and `Attrs`. The `Type` property must be set to \'moby\'. The `Attrs` property is a map of attributes for the BuildKit output configuration. See https://docs.docker.com/build/exporters/oci-docker/ for more information. Example: ``` [{\"Type\":\"moby\",\"Attrs\":{\"type\":\"image\",\"force-compression\":\"true\",\"compression\":\"zstd\"}}] ```
* @param options.version Version of the builder backend to use. - `1` is the first generation classic (deprecated) builder in the Docker daemon (default) - `2` is [BuildKit](https://github.com/moby/buildkit)
*/
public async *imageBuild(
buildContext: ReadableStream,
Expand Down
4 changes: 2 additions & 2 deletions lib/filter.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
export class Filter {
private data: Map<string, Set<string>> = new Map();
set(key: string, values: string[]): Filter {
set(key: string, values: string[]): this {
this.data.set(key, new Set(values));
return this;
}

add(key: string, value: string): Filter {
add(key: string, value: string): this {
if (!this.data.has(key)) {
this.data.set(key, new Set());
}
Expand Down
4 changes: 2 additions & 2 deletions lib/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function _getErrorMessageFromResp(
if (contentType?.includes(APPLICATION_JSON) && body) {
const jsonBody = JSON.parse(body);
if (jsonBody.message) {
return jsonBody.message;
return jsonBody.message as string;
}
}
return res.statusMessage;
Expand Down Expand Up @@ -253,7 +253,7 @@ export class HTTPClient {
if (Array.isArray(header)) {
content = header[0] || '';
} else {
content = header as string;
content = header;
}

return {
Expand Down
Loading