From 38fc8aa0f8726fdfb5eea06d6b8825093c9127ec Mon Sep 17 00:00:00 2001 From: Gustavo Perdomo Date: Sat, 7 Dec 2024 22:06:31 -0300 Subject: [PATCH] feat(nx-container): improvements in inferred task --- plugins/nx-container/README.md | 40 ++++++++------ plugins/nx-container/package.json | 2 +- .../src/generators/configuration/constants.ts | 1 + .../nx-container/src/generators/init/init.ts | 20 ++++--- .../src/generators/init/schema.d.ts | 1 + .../src/generators/init/schema.json | 6 +++ plugins/nx-container/src/plugins/nodes.ts | 54 ++++++++++++------- 7 files changed, 82 insertions(+), 42 deletions(-) diff --git a/plugins/nx-container/README.md b/plugins/nx-container/README.md index 9a806ec4..0700cc66 100644 --- a/plugins/nx-container/README.md +++ b/plugins/nx-container/README.md @@ -19,30 +19,38 @@ This executor not handle registry login steps, so if you wanna push your contain Adding the Container plugin to an existing Nx workspace can be done with the following: ```bash -npm install -D @nx-tools/nx-container +nx add @nx-tools/nx-container ``` -```bash -yarn add -D @nx-tools/nx-container -``` +## Using the Container Plugin -If you want an "automatic" tag management and [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md) for labels, you need to install the optional `@nx-tools/container-metadata` package: +### Configuring an application -```bash -npm install -D @nx-tools/container-metadata -``` +It's straightforward to setup your application: -```bash -yarn add -D @nx-tools/container-metadata +#### Using Inferred target (Project Crystal): + +It's straightforward to setup your application with 2 simple steps + +1. Run this command `nx g @nx-tools/nx-container:init` or add nx-container manually to the plugins array in your `nx.json` file, like is showed below: + +``` + { + "plugin": "@nx-tools/nx-container", + "options": { + "defaultEngine": "docker", + "defaultRegistry": "docker.io" + } + } ``` -> @nx-tools/container-metadata is the succesor of `@nx-tools/docker-metadata`. +2. Add a`Dockerfile` to your application -## Using the Container Plugin +> Note: This requires `@nx-tools/nx-container`verion `6.2.0` or above. -### Configuring an application +#### Manual configuration -It's straightforward to setup your application: +To setup a `container` task, or override inferred task, you can use this command: ```bash nx g @nx-tools/nx-container:configuration appName @@ -50,11 +58,13 @@ nx g @nx-tools/nx-container:configuration appName By default, the application will be configured with: -- A Dockerfile in the application root. +- A Dockerfile in the application root (Will be created if no Dockerfile is present in app directory) - A target to build your application using the Docker engine. We can then build our application with the following command: +### Build your application + ```bash nx container appName ``` diff --git a/plugins/nx-container/package.json b/plugins/nx-container/package.json index ec23908e..114de3e4 100644 --- a/plugins/nx-container/package.json +++ b/plugins/nx-container/package.json @@ -1,6 +1,6 @@ { "name": "@nx-tools/nx-container", - "version": "6.1.1", + "version": "6.2.0", "author": "gperdomor ", "repository": "https://github.com/gperdomor/nx-tools", "bugs": "https://github.com/gperdomor/nx-tools/issues", diff --git a/plugins/nx-container/src/generators/configuration/constants.ts b/plugins/nx-container/src/generators/configuration/constants.ts index 5ed96c14..1a71fc7c 100644 --- a/plugins/nx-container/src/generators/configuration/constants.ts +++ b/plugins/nx-container/src/generators/configuration/constants.ts @@ -1,3 +1,4 @@ export const DEFAULT_ENGINE = 'docker'; +export const DEFAULT_REGISTRY = 'docker.io'; export const DEFAULT_TEMPLATE = 'empty'; diff --git a/plugins/nx-container/src/generators/init/init.ts b/plugins/nx-container/src/generators/init/init.ts index ad801c45..28f1613d 100644 --- a/plugins/nx-container/src/generators/init/init.ts +++ b/plugins/nx-container/src/generators/init/init.ts @@ -1,6 +1,14 @@ -import { GeneratorCallback, PluginConfiguration, readNxJson, runTasksInSerial, Tree, updateNxJson } from '@nx/devkit'; +import { + ExpandedPluginConfiguration, + GeneratorCallback, + PluginConfiguration, + readNxJson, + runTasksInSerial, + Tree, + updateNxJson, +} from '@nx/devkit'; +import { ContainerPluginOptions } from '../../plugins'; import { Schema } from './schema'; -import { DEFAULT_ENGINE } from '../configuration/constants'; export async function initGenerator(tree: Tree, options: Schema): Promise { const tasks: GeneratorCallback[] = []; @@ -10,10 +18,10 @@ export async function initGenerator(tree: Tree, options: Schema): Promise = { + plugin: '@nx-tools/nx-container', + options: { defaultEngine: options.defaultEngine, defaultRegistry: options.defaultRegistry }, + }; nxJson.plugins.push(pluginConfig); updateNxJson(tree, nxJson); diff --git a/plugins/nx-container/src/generators/init/schema.d.ts b/plugins/nx-container/src/generators/init/schema.d.ts index 4005b69f..c6f0d28b 100644 --- a/plugins/nx-container/src/generators/init/schema.d.ts +++ b/plugins/nx-container/src/generators/init/schema.d.ts @@ -3,4 +3,5 @@ export interface Schema { * Provide the default container engine to be used. */ defaultEngine?: 'docker' | 'podman' | 'kaniko'; + defaultRegistry?: string; } diff --git a/plugins/nx-container/src/generators/init/schema.json b/plugins/nx-container/src/generators/init/schema.json index 8531f528..a3480be2 100644 --- a/plugins/nx-container/src/generators/init/schema.json +++ b/plugins/nx-container/src/generators/init/schema.json @@ -29,6 +29,12 @@ ] }, "alias": "e" + }, + "defaultRegistry": { + "type": "string", + "description": "Provide the default registry to be used.", + "default": "docker.io", + "alias": "r" } } } diff --git a/plugins/nx-container/src/plugins/nodes.ts b/plugins/nx-container/src/plugins/nodes.ts index 52cca474..80559703 100644 --- a/plugins/nx-container/src/plugins/nodes.ts +++ b/plugins/nx-container/src/plugins/nodes.ts @@ -7,16 +7,17 @@ import { TargetConfiguration, writeJsonFile, } from '@nx/devkit'; -import { dirname, join } from 'path'; +import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; import { getLockFileName } from '@nx/js'; import { existsSync, readdirSync, readFileSync } from 'fs'; -import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; -import { DEFAULT_ENGINE } from '../generators/configuration/constants'; +import { dirname, join } from 'path'; +import { DEFAULT_ENGINE, DEFAULT_REGISTRY } from '../generators/configuration/constants'; export interface ContainerPluginOptions { buildTargetName?: string; defaultEngine?: string; + defaultRegistry?: string; } const cachePath = join(workspaceDataDirectory, 'container.hash'); @@ -41,9 +42,9 @@ export const createNodes: CreateNodes = [ options = normalizeOptions(options); const projectRoot = dirname(configFilePath); - // Do not create a project if project.json isn't there. + // Do not create a project if package.json and project.json isn't there. const siblingFiles = readdirSync(join(context.workspaceRoot, projectRoot)); - if (!siblingFiles.includes('project.json')) { + if (!siblingFiles.includes('package.json') && !siblingFiles.includes('project.json')) { return {}; } @@ -51,7 +52,7 @@ export const createNodes: CreateNodes = [ getLockFileName(detectPackageManager(context.workspaceRoot)), ]); - const projectName = buildProjectName(projectRoot, context.workspaceRoot); + const projectName = buildProjectName(projectRoot, context.workspaceRoot, options); targetsCache[hash] ??= buildTargets(projectRoot, options, projectName); @@ -72,16 +73,23 @@ function buildTargets(projectRoot: string, options: ContainerPluginOptions, proj dependsOn: ['build'], options: { engine: options.defaultEngine, - metadata: { - images: [projectName], - load: true, - tags: [ - 'type=schedule', - 'type=ref,event=branch', - 'type=ref,event=tag', - 'type=ref,event=pr', - 'type=sha,prefix=sha-', - ], + tags: [`${projectName}:dev`], + load: true, + }, + configurations: { + ci: { + load: false, + push: true, + metadata: { + images: [projectName], + tags: [ + 'type=schedule', + 'type=ref,event=branch', + 'type=ref,event=tag', + 'type=ref,event=pr', + 'type=sha,prefix=sha-', + ], + }, }, }, }, @@ -90,23 +98,29 @@ function buildTargets(projectRoot: string, options: ContainerPluginOptions, proj return targets; } -function buildProjectName(projectRoot: string, workspaceRoot: string): string | undefined { +function buildProjectName( + projectRoot: string, + workspaceRoot: string, + options: ContainerPluginOptions +): string | undefined { const packageJsonPath = join(workspaceRoot, projectRoot, 'package.json'); const projectJsonPath = join(workspaceRoot, projectRoot, 'project.json'); let name: string; + const registry = options.defaultRegistry.length ? `${options.defaultRegistry}/` : ''; if (existsSync(projectJsonPath)) { const projectJson = parseJson(readFileSync(projectJsonPath, 'utf-8')); - name = projectJson.name; + name = `${registry}${projectJson.name}`; } else if (existsSync(packageJsonPath)) { const packageJson = parseJson(readFileSync(packageJsonPath, 'utf-8')); - name = packageJson.name; + name = `${registry}${packageJson.name}`; } - return name; + return name.replace(/@/gi, ''); } function normalizeOptions(options: ContainerPluginOptions): ContainerPluginOptions { options ??= {}; options.buildTargetName ??= 'container'; options.defaultEngine ??= DEFAULT_ENGINE; + options.defaultRegistry ??= DEFAULT_REGISTRY; return options; }