Skip to content

Commit

Permalink
adjust: plugin options and add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
BioPhoton committed Sep 19, 2024
1 parent f781c5e commit b605a17
Show file tree
Hide file tree
Showing 25 changed files with 462 additions and 147 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ In the below we point out a **scalable** and **maintainable** setup for Verdacci
> [!NOTE]
> If you want to read about common problems with a shared environment read the [docs/motivation.md](./docs/motivation.md).
### 🛡️ Isolation of Files During E2E Tests
### 🛡️ Environment Folders to Isolate Files During E2E Tests

All files that change during testing are contained within an isolated folder, ensuring they don't interfere with your local setup or other tests.

Expand All @@ -206,7 +206,7 @@ Root/
│ └── packages/
│ └── <project-name>/...
├── tmp/
│ └── e2e/
│ └── environments/
│ └── <project-name>/
│ ├── storage/... # npm publish/unpublish
│ │ └── <org>
Expand Down
81 changes: 81 additions & 0 deletions projects/build-env/src/executors/bootstrap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Bootstrap Environment Executor

This executor helps to initiate [environment](../../../../../README.md#-environment-folders-to-isolate-files-during-e2e-tests) into a given folder.
This folder contains all needed configuration and files for a Verdaccio registry as well as the package manager configuration.

**Environment folder**

```bash

```sh
Root/
└── tmp/
└── environments/
└── <project-name>/
├── storage/... # npm publish/unpublish
│ └── <org>
│ └── <package-name>/...
├── node_modules/ # npm install/uninstall
│ └── <org>
│ └── <package-name>/...
├── __test__/...
│ └── <test-file-name>/...
│ └── <it-block-setup>/...
│ └── test.file.ts
├── .npmrc # local npm config configured for project specific Verdaccio registry
├── package-lock.json # skipped creation by default
└── package.json # npm install/uninstall
```

#### @push-based/build-env:env-bootstrap

> [!notice]
> The bootstrap executor keeps the Verdaccio server running.
> To stop the server **`nx run <project-name>:build-env--verdaccio-stop --environmentRoot path/to/environment`**
> To avoid keeping the server running pass **`--no-keepServerRunning`**

## Usage

// project.json

```json
{
"name": "my-project",
"targets": {
"build-env--env-bootstrap": {
"executor": "@push-based/build-env:env-bootstrap"
}
}
}
```

By default, the Nx executor will derive the options from the executor options.

```jsonc
{
"name": "my-project",
"targets": {
"build-env--env-bootstrap": {
"executor": "@code-pushup/build-env:env-bootstrap",
"options": {
"keepServerRunning": false
"envRoot": "/tmp/test-npm-workspace"
"verbose": true,
}
}
}
}
```

Show what will be executed without actually executing it:

`nx run my-project:build-env--env-bootstrap --print-config`

## Options

| Name | type | description |
|-----------------------|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| **envRoot** | `string` (REQUIRED) | The folder in which the package should get published. This folder is the environment folder and contains a configured `.npmrc` file. |
| **keepServerRunning** | `boolean` (DEFAULT true) | keep the Verdaccio server running after bootstraping the environment |
| **printConfig** | `boolean` | Print config without executing |
| **verbose** | `boolean` | Show more verbose logs |
64 changes: 43 additions & 21 deletions projects/build-env/src/executors/bootstrap/bootstrap-env.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,54 @@
import { join } from 'node:path';
import {join} from 'node:path';
import {
startVerdaccioServer,
type StarVerdaccioOptions,
type VercaddioServerResult,
} from './verdaccio-registry';
import { writeFile } from 'node:fs/promises';
import { setupNpmWorkspace } from './npm';
import { formatInfo } from '../../internal/logging';
import { VERDACCIO_REGISTRY_JSON } from './constants';
import { logger } from '@nx/devkit';
import {writeFile} from 'node:fs/promises';
import {setupNpmWorkspace} from './npm';
import {formatInfo} from '../../internal/logging';
import {VERDACCIO_REGISTRY_JSON} from './constants';
import {ExecutorContext, logger} from '@nx/devkit';
import {
configureRegistry,
type Environment,
VERDACCIO_ENV_TOKEN,
} from './npm';
import runKillProcessExecutor from "../kill-process/executor";

export type BootstrapEnvironmentOptions = Partial<
StarVerdaccioOptions & Environment
> &
Required<Pick<StarVerdaccioOptions, 'projectName'>>;
> & {
keepServerRunning?: boolean,
projectName: string;
environmentRoot: string;
};

export type BootstrapEnvironmentResult = Environment & {
registry: VercaddioServerResult;
stop: () => void;
};

export async function bootstrapEnvironment({
verbose = false,
environmentRoot,
...opts
}: BootstrapEnvironmentOptions & {
environmentRoot: string;
}): Promise<BootstrapEnvironmentResult> {
verbose,
environmentRoot,
keepServerRunning = true,
...opts
}: BootstrapEnvironmentOptions, context: ExecutorContext): Promise<BootstrapEnvironmentResult> {

const storage = join(environmentRoot, 'storage');
const {projectName} = context;
const registryResult = await startVerdaccioServer({
storage,
verbose,
projectName,
readyWhen: 'Environment ready under',
...opts,
});

await setupNpmWorkspace(environmentRoot, verbose);
const userconfig = join(environmentRoot, '.npmrc');
configureRegistry({ ...registryResult.registry, userconfig }, verbose);
configureRegistry({...registryResult.registry, userconfig}, verbose);

const activeRegistry: BootstrapEnvironmentResult = {
...registryResult,
Expand All @@ -59,12 +66,27 @@ export async function bootstrapEnvironment({
JSON.stringify(activeRegistry.registry, null, 2)
);

logger.info(
formatInfo(
`Environment ready under: ${activeRegistry.root}`,
VERDACCIO_ENV_TOKEN
)
);
if (keepServerRunning) {
logger.info(
formatInfo(
`Environment ready under: ${activeRegistry.root}`,
VERDACCIO_ENV_TOKEN
)
);
logger.info(
formatInfo(
`Verdaccio server is running on ${activeRegistry.registry.url}`,
VERDACCIO_ENV_TOKEN
)
);
} else {
await runKillProcessExecutor(
{
filePath: join(environmentRoot, VERDACCIO_REGISTRY_JSON),
},
context
);
}

return activeRegistry;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from 'vitest';
import { bootstrapEnvironment } from './bootstrap-env';
import { runBootstrapEnvironment } from './bootstrap-env';
import * as verdaccioRegistryModule from './verdaccio-registry';
import * as npmModule from './npm';
import * as fs from 'node:fs/promises';
Expand Down Expand Up @@ -46,7 +46,7 @@ describe('bootstrapEnvironment', () => {

it('should create environment', async () => {
await expect(
bootstrapEnvironment({
runBootstrapEnvironment({
projectName: 'my-lib-e2e',
environmentRoot: 'tmp/environments/my-lib-e2e',
})
Expand Down
21 changes: 11 additions & 10 deletions projects/build-env/src/executors/bootstrap/executor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type ExecutorContext, logger } from '@nx/devkit';
import type { BootstrapExecutorOptions } from './schema';
import { bootstrapEnvironment } from './bootstrap-env';
import { normalizeOptions } from '../internal/normalize-options';
import {type ExecutorContext, logger} from '@nx/devkit';
import type {BootstrapExecutorOptions} from './schema';
import {bootstrapEnvironment} from './bootstrap-env';
import {normalizeExecutorOptions} from '../internal/normalize-options';

export type BootstrapExecutorOutput = {
success: boolean;
Expand All @@ -13,24 +13,25 @@ export default async function runBootstrapExecutor(
options: BootstrapExecutorOptions,
context: ExecutorContext
) {
const { projectName, options: normalizedOptions } = normalizeOptions(
const { options: normalizedOptions} = normalizeExecutorOptions(
context,
options
);
context.projectName

logger.info(
`Execute @push-based/build-env:build with options: ${JSON.stringify(
`Execute @push-based/build-env:bootstrap with options: ${JSON.stringify(
options,
null,
2
)}`
);


try {
await bootstrapEnvironment({
...normalizedOptions,
projectName,
readyWhen: 'Environment ready under',
});
...normalizedOptions
}, context);
} catch (error) {
logger.error(error);
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ vi.mock('@nx/devkit', async () => {

describe('runBootstrapExecutor', () => {
const bootstrapEnvironmentSpy = vi
.spyOn(bootstrapEnvModule, 'bootstrapEnvironment')
.spyOn(bootstrapEnvModule, 'runBootstrapEnvironment')
.mockResolvedValue({
registry: {
host: 'localhost',
Expand Down Expand Up @@ -61,7 +61,7 @@ describe('runBootstrapExecutor', () => {
expect(logger.error).not.toHaveBeenCalled();
expect(logger.info).toHaveBeenCalledTimes(1);
expect(logger.info).toHaveBeenCalledWith(
'Execute @push-based/build-env:build with options: {}'
'Execute @push-based/build-env:bootstrap with options: {}'
);

expect(bootstrapEnvironmentSpy).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -135,7 +135,7 @@ describe('runBootstrapExecutor', () => {

expect(logger.info).toHaveBeenCalledTimes(1);
expect(logger.info).toHaveBeenCalledWith(
'Execute @push-based/build-env:build with options: {}'
'Execute @push-based/build-env:bootstrap with options: {}'
);

expect(logger.error).toHaveBeenCalledTimes(1);
Expand Down
12 changes: 10 additions & 2 deletions projects/build-env/src/executors/bootstrap/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
"type": "string",
"description": "The root directory of the environment"
},
"dryRun": {
"keepServerRunning": {
"type": "boolean",
"description": "Keep the server running after the bootstrap commands have been executed",
"default": false
},
"printConfig": {
"type": "boolean",
"description": "Print the commands that would be run, but don't actually run them"
},
Expand All @@ -17,5 +22,8 @@
"description": "Print additional logs"
}
},
"additionalProperties": true
"additionalProperties": true,
"required": [
"environmentRoot"
]
}
3 changes: 2 additions & 1 deletion projects/build-env/src/executors/bootstrap/schema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export type BootstrapExecutorOptions = Partial<{
keepServerRunning: boolean;
environmentRoot: string;
dryRun: boolean;
printConfig: boolean;
verbose: boolean;
}>;
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { executeProcess } from '../../internal/execute-process';
import { uniquePort } from './unique-port';
import { getEnvironmentsRoot } from '../../internal/setup';
import { formatError, formatInfo } from '../../internal/logging';
import {DEFAULT_START_VERDACCIO_TARGET} from "../../internal/constants";

const VERDACCIO_TOKEN = 'Verdaccio: ';

Expand Down Expand Up @@ -77,10 +78,10 @@ export type StarVerdaccioOptions = VerdaccioExecuterOptions &
StarVerdaccioOnlyOptions;

export async function startVerdaccioServer({
targetName = 'start-verdaccio',
targetName = DEFAULT_START_VERDACCIO_TARGET,
projectName,
port = String(uniquePort()),
storage = join(getEnvironmentsRoot(projectName), targetName, 'storage'),
storage = join(getEnvironmentsRoot(projectName), 'storage'),
location = 'none',
clear = true,
verbose = true,
Expand Down
14 changes: 3 additions & 11 deletions projects/build-env/src/executors/internal/normalize-options.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { join } from 'node:path';
import { DEFAULT_ENVIRONMENTS_OUTPUT_DIR } from '../../internal/constants';
import type { ExecutorContext } from '@nx/devkit';
import type {ExecutorContext} from '@nx/devkit';

export function normalizeOptions<
export function normalizeExecutorOptions<
T extends ExecutorContext,
I extends Record<string, unknown> & {
environmentProject?: string;
Expand All @@ -14,16 +12,10 @@ export function normalizeOptions<
): T & {
options: I & { environmentRoot: string };
} {
const { projectName } = context;
const { environmentProject = projectName, environmentRoot } = options;
return {
...context,
options: {
...options,
environmentProject,
environmentRoot:
environmentRoot ??
join(DEFAULT_ENVIRONMENTS_OUTPUT_DIR, environmentProject),
...options
},
};
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { describe, expect } from 'vitest';
import { normalizeOptions } from './normalize-options';
import { normalizeExecutorOptions } from './normalize-options';
import type { ExecutorContext } from '@nx/devkit';

describe('normalizeOptions', () => {
it('should normalize options', () => {
expect(
normalizeOptions({ projectName: 'test' } as ExecutorContext, {
normalizeExecutorOptions({ projectName: 'test' } as ExecutorContext, {
environmentProject: 'test',
})
).toEqual({
Expand All @@ -19,7 +19,7 @@ describe('normalizeOptions', () => {

it('should normalize options with given environmentRoot to ', () => {
expect(
normalizeOptions({ projectName: 'test' } as ExecutorContext, {
normalizeExecutorOptions({ projectName: 'test' } as ExecutorContext, {
environmentProject: 'test',
environmentRoot: 'static-e2e-environments/dummy-react-app',
})
Expand Down
Loading

0 comments on commit b605a17

Please sign in to comment.