feat(node): add docker as a build target (#14475)
This commit is contained in:
parent
7857ae00a0
commit
0e018e620e
@ -5015,6 +5015,14 @@
|
||||
"children": [],
|
||||
"isExternal": false,
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"id": "setup-docker",
|
||||
"path": "/packages/node/generators/setup-docker",
|
||||
"name": "setup-docker",
|
||||
"children": [],
|
||||
"isExternal": false,
|
||||
"disableCollapsible": false
|
||||
}
|
||||
],
|
||||
"isExternal": false,
|
||||
|
||||
@ -1554,6 +1554,15 @@
|
||||
"originalFilePath": "/packages/node/src/generators/library/schema.json",
|
||||
"path": "/packages/node/generators/library",
|
||||
"type": "generator"
|
||||
},
|
||||
"/packages/node/generators/setup-docker": {
|
||||
"description": "Set up Docker configuration for a project.",
|
||||
"file": "generated/packages/node/generators/setup-docker.json",
|
||||
"hidden": false,
|
||||
"name": "setup-docker",
|
||||
"originalFilePath": "/packages/node/src/generators/setup-docker/schema.json",
|
||||
"path": "/packages/node/generators/setup-docker",
|
||||
"type": "generator"
|
||||
}
|
||||
},
|
||||
"path": "/packages/node"
|
||||
|
||||
@ -1531,6 +1531,15 @@
|
||||
"originalFilePath": "/packages/node/src/generators/library/schema.json",
|
||||
"path": "node/generators/library",
|
||||
"type": "generator"
|
||||
},
|
||||
{
|
||||
"description": "Set up Docker configuration for a project.",
|
||||
"file": "generated/packages/node/generators/setup-docker.json",
|
||||
"hidden": false,
|
||||
"name": "setup-docker",
|
||||
"originalFilePath": "/packages/node/src/generators/setup-docker/schema.json",
|
||||
"path": "node/generators/setup-docker",
|
||||
"type": "generator"
|
||||
}
|
||||
],
|
||||
"githubRoot": "https://github.com/nrwl/nx/blob/master",
|
||||
|
||||
@ -110,6 +110,10 @@
|
||||
"enum": ["jest", "none"],
|
||||
"description": "Test runner to use for end to end (e2e) tests",
|
||||
"default": "jest"
|
||||
},
|
||||
"docker": {
|
||||
"type": "boolean",
|
||||
"description": "Add a docker build target"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
36
docs/generated/packages/node/generators/setup-docker.json
Normal file
36
docs/generated/packages/node/generators/setup-docker.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "setup-docker",
|
||||
"factory": "./src/generators/setup-docker/setup-docker",
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"cli": "nx",
|
||||
"$id": "SchematicsNxSetupDocker",
|
||||
"title": "Nx Node Docker Options Schema",
|
||||
"description": "Nx Node Docker Options Schema.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"projectName": {
|
||||
"description": "The name of the project",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"type": "string"
|
||||
},
|
||||
"targetName": {
|
||||
"description": "The name of the target to create",
|
||||
"type": "string",
|
||||
"default": "docker-build"
|
||||
},
|
||||
"buildTargetName": {
|
||||
"description": "The name of the build target",
|
||||
"type": "string",
|
||||
"default": "build"
|
||||
}
|
||||
},
|
||||
"presets": []
|
||||
},
|
||||
"description": "Set up Docker configuration for a project.",
|
||||
"hidden": false,
|
||||
"implementation": "/packages/node/src/generators/setup-docker/setup-docker.ts",
|
||||
"aliases": [],
|
||||
"path": "/packages/node/src/generators/setup-docker/schema.json",
|
||||
"type": "generator"
|
||||
}
|
||||
@ -23,6 +23,12 @@
|
||||
"aliases": ["lib"],
|
||||
"x-type": "library",
|
||||
"description": "Create a node library."
|
||||
},
|
||||
"setup-docker": {
|
||||
"factory": "./src/generators/setup-docker/setup-docker",
|
||||
"schema": "./src/generators/setup-docker/schema.json",
|
||||
"description": "Set up Docker configuration for a project.",
|
||||
"hidden": false
|
||||
}
|
||||
},
|
||||
"schematics": {
|
||||
@ -46,6 +52,11 @@
|
||||
"aliases": ["lib"],
|
||||
"x-type": "library",
|
||||
"description": "Create a node library."
|
||||
},
|
||||
"setup-docker": {
|
||||
"factory": "./src/generators/setup-docker/setup-docker#setupDockerGenerator",
|
||||
"schema": "./src/generators/setup-docker/schema.json",
|
||||
"description": "Set up Docker configuration for a project."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ import {
|
||||
|
||||
import * as shared from '@nrwl/workspace/src/utils/create-ts-config';
|
||||
import { e2eProjectGenerator } from '../e2e-project/e2e-project';
|
||||
import { setupDockerGenerator } from '../setup-docker/setup-docker';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
appProjectRoot: string;
|
||||
@ -374,6 +375,15 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||
addProxy(tree, options);
|
||||
}
|
||||
|
||||
if (options.docker) {
|
||||
const dockerTask = await setupDockerGenerator(tree, {
|
||||
...options,
|
||||
projectName: options.name,
|
||||
});
|
||||
|
||||
tasks.push(dockerTask);
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ export interface Schema {
|
||||
framework?: NodeJsFrameWorks;
|
||||
port?: number;
|
||||
rootProject?: boolean;
|
||||
docker?: boolean;
|
||||
}
|
||||
|
||||
export type NodeJsFrameWorks =
|
||||
|
||||
@ -110,6 +110,10 @@
|
||||
"enum": ["jest", "none"],
|
||||
"description": "Test runner to use for end to end (e2e) tests",
|
||||
"default": "jest"
|
||||
},
|
||||
"docker": {
|
||||
"type": "boolean",
|
||||
"description": "Add a docker build target"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
FROM docker.io/node:lts-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN addgroup --system <%= projectName %> && \
|
||||
adduser --system -G <%= projectName %> <%= projectName %>
|
||||
|
||||
COPY <%= buildLocation %> dist
|
||||
RUN chown -R <%= projectName %>:<%= projectName %> .
|
||||
|
||||
CMD [ "node", "dist" ]
|
||||
6
packages/node/src/generators/setup-docker/schema.d.ts
vendored
Normal file
6
packages/node/src/generators/setup-docker/schema.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export interface SetUpDockerOptions {
|
||||
projectName?: string;
|
||||
targetName?: string;
|
||||
buildTarget?: string;
|
||||
skipFormat?: boolean;
|
||||
}
|
||||
25
packages/node/src/generators/setup-docker/schema.json
Normal file
25
packages/node/src/generators/setup-docker/schema.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"cli": "nx",
|
||||
"$id": "SchematicsNxSetupDocker",
|
||||
"title": "Nx Node Docker Options Schema",
|
||||
"description": "Nx Node Docker Options Schema.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"projectName": {
|
||||
"description": "The name of the project",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"type": "string"
|
||||
},
|
||||
"targetName": {
|
||||
"description": "The name of the target to create",
|
||||
"type": "string",
|
||||
"default": "docker-build"
|
||||
},
|
||||
"buildTargetName": {
|
||||
"description": "The name of the build target",
|
||||
"type": "string",
|
||||
"default": "build"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
import { readProjectConfiguration, Tree } from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import { applicationGenerator } from '../application/application';
|
||||
describe('setupDockerGenerator', () => {
|
||||
let tree: Tree;
|
||||
beforeEach(async () => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
});
|
||||
|
||||
describe('integrated', () => {
|
||||
it('should create docker assets when --docker is passed', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
name: 'api',
|
||||
framework: 'express',
|
||||
e2eTestRunner: 'none',
|
||||
docker: true,
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'api');
|
||||
|
||||
expect(tree.exists('api/Dockerfile')).toBeTruthy();
|
||||
expect(project.targets).toEqual(
|
||||
expect.objectContaining({
|
||||
'docker-build': {
|
||||
dependsOn: ['build'],
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
commands: ['docker build -f api/Dockerfile .'],
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('standalone', () => {
|
||||
it('should create docker assets when --docker is passed', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
name: 'api',
|
||||
framework: 'fastify',
|
||||
rootProject: true,
|
||||
docker: true,
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'api');
|
||||
expect(tree.exists('Dockerfile')).toBeTruthy();
|
||||
expect(project.targets).toEqual(
|
||||
expect.objectContaining({
|
||||
'docker-build': {
|
||||
dependsOn: ['build'],
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
commands: ['docker build -f Dockerfile .'],
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
88
packages/node/src/generators/setup-docker/setup-docker.ts
Normal file
88
packages/node/src/generators/setup-docker/setup-docker.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
convertNxGenerator,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
GeneratorCallback,
|
||||
joinPathFragments,
|
||||
logger,
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||
import { SetUpDockerOptions } from './schema';
|
||||
|
||||
function normalizeOptions(
|
||||
tree: Tree,
|
||||
setupOptions: SetUpDockerOptions
|
||||
): SetUpDockerOptions {
|
||||
return {
|
||||
...setupOptions,
|
||||
projectName: setupOptions.projectName ?? readNxJson(tree).defaultProject,
|
||||
targetName: setupOptions.targetName ?? 'docker-build',
|
||||
buildTarget: setupOptions.buildTarget ?? 'build',
|
||||
};
|
||||
}
|
||||
|
||||
function addDocker(tree: Tree, options: SetUpDockerOptions) {
|
||||
const project = readProjectConfiguration(tree, options.projectName);
|
||||
if (!project || !options.targetName) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tree.exists(joinPathFragments(project.root, 'DockerFile'))) {
|
||||
logger.info(
|
||||
`Skipping setup since a Dockerfile already exists inside ${project.root}`
|
||||
);
|
||||
} else {
|
||||
const outputPath =
|
||||
project.targets[`${options.buildTarget}`]?.options.outputPath;
|
||||
generateFiles(tree, joinPathFragments(__dirname, './files'), project.root, {
|
||||
tmpl: '',
|
||||
app: project.sourceRoot,
|
||||
buildLocation: outputPath,
|
||||
projectName: options.projectName,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function updateProjectConfig(tree: Tree, options: SetUpDockerOptions) {
|
||||
let projectConfig = readProjectConfiguration(tree, options.projectName);
|
||||
|
||||
projectConfig.targets[`${options.targetName}`] = {
|
||||
dependsOn: [`${options.buildTarget}`],
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
commands: [
|
||||
`docker build -f ${joinPathFragments(
|
||||
projectConfig.root,
|
||||
'Dockerfile'
|
||||
)} .`,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
updateProjectConfiguration(tree, options.projectName, projectConfig);
|
||||
}
|
||||
|
||||
export async function setupDockerGenerator(
|
||||
tree: Tree,
|
||||
setupOptions: SetUpDockerOptions
|
||||
) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const options = normalizeOptions(tree, setupOptions);
|
||||
// Should check if the node project exists
|
||||
addDocker(tree, options);
|
||||
updateProjectConfig(tree, options);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export default setupDockerGenerator;
|
||||
export const setupDockerSchematic = convertNxGenerator(setupDockerGenerator);
|
||||
Loading…
x
Reference in New Issue
Block a user