Skip to content

Commit

Permalink
feat: add env-teardown executor
Browse files Browse the repository at this point in the history
  • Loading branch information
BioPhoton committed Oct 13, 2024
1 parent 41bf879 commit 33b1d3b
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 1 deletion.
3 changes: 3 additions & 0 deletions examples/e2e/models-e2e/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
"implicitDependencies": ["models"],
"targets": {
"lint": {},
"teardown": {
"executor": "@push-based/nx-verdaccio:env-teardown"
},
"e2e": {
"executor": "@nx/vite:test",
"inputs": ["default", "^production"],
Expand Down
53 changes: 53 additions & 0 deletions projects/nx-verdaccio/src/executors/env-teardown/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Teardown Environment Executor

This executor helps to cleanup a [environment](../../../../../README.md#-environment-folders-to-isolate-files-during-e2e-tests) of a given folder.
If a server is running for the given environment, it will be stopped.
If this folder is checked into github all it's changes will be reverted, if it is not checked into github, the folder will be deleted.

**Environment folder**

#### @push-based/nx-verdaccio:env-teardown

## Usage

// project.json

```json
{
"name": "my-project",
"targets": {
"env-teardown": {
"executor": "@push-based/nx-verdaccio:env-teardown"
}
}
}
```

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

```jsonc
{
"name": "my-project",
"targets": {
"env-teardown": {
"executor": "@code-pushup/nx-verdaccio:env-teardown",
"options": {
"envRoot": "/tmp/test-npm-workspace"
"verbose": true,
}
}
}
}
```

Show what will be executed without actually executing it:

`nx run my-project:env-teardown --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. |
| **verbose** | `boolean` | Show more verbose logs |
| **printConfig** | `boolean` | Print config without executing |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const EXECUTOR_ENVIRONMENT_TEARDOWN = 'env-teardown';
42 changes: 42 additions & 0 deletions projects/nx-verdaccio/src/executors/env-teardown/executor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {type ExecutorContext, logger} from '@nx/devkit';
import type {TeardownExecutorOptions} from './schema';
import {teardownEnvironment,} from './teardown-env';
import {PACKAGE_NAME} from '../../plugin/constants';
import {EXECUTOR_ENVIRONMENT_TEARDOWN} from "./constants";
import {ExecutorOutput} from "../internal/executor-output";

export async function teardownExecutor(
options: TeardownExecutorOptions,
context: ExecutorContext
): Promise<ExecutorOutput> {
const { environmentRoot, verbose } = options;

if (verbose) {
logger.info(
`Execute ${PACKAGE_NAME}:${EXECUTOR_ENVIRONMENT_TEARDOWN} with options: ${JSON.stringify(
options,
null,
2
)}`
);
}
try {
await teardownEnvironment(context, {
environmentRoot,
verbose,
});
} catch (error) {
logger.error(error);
return {
success: false,
command: error?.message ?? (error as Error).toString(),
};
}

return {
success: true,
command: 'Teared down environment successfully.',
};
}

export default teardownExecutor;
54 changes: 54 additions & 0 deletions projects/nx-verdaccio/src/executors/env-teardown/git.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type {SimpleGit} from "simple-git";
import {simpleGit} from "simple-git";
import {resolve} from "node:path";

export const gitClient: SimpleGit = simpleGit();

export async function cleanGitHistoryForFolder(
environmentRoot: string,
options?: { verbose?: boolean },
git: SimpleGit = gitClient
): Promise<void> {

await git.show(['--oneline']);

}

export async function isFolderInRepo(
folderPath: string
): Promise<boolean> {
// Initialize simple-git with the folder path
const git = simpleGit(folderPath);

try {
// Check if the folder is a git repository
const isRepo = (await git.checkIgnore(folderPath)).length === 0
// console.log(`${folderPath} is ${isRepo ? '' : 'not '} in Git repository.`);
return isRepo;
} catch (error) {
console.log(`${error}`);
return false;
}
}

export async function isSubfolderInGitRepository(subFolderPath: string, baseFolderPath = process.cwd()) {
// Resolve the full path for the subfolder
const fullSubFolderPath = resolve(baseFolderPath, subFolderPath);

// Initialize simple-git with the full subfolder path
const git = simpleGit(fullSubFolderPath);

try {
// Check if the subfolder path is within a Git repository
const isRepo = await git.checkIsRepo();
if (isRepo) {
console.log(`${fullSubFolderPath} is inside a Git repository.`);
} else {
console.log(`${fullSubFolderPath} is not inside a Git repository.`);
}
return isRepo;
} catch (error) {
console.log(`${fullSubFolderPath} is not inside a Git repository.`);
return false;
}
}
11 changes: 11 additions & 0 deletions projects/nx-verdaccio/src/executors/env-teardown/git.unit-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {describe, expect, it, vi} from 'vitest';
import {cleanGitHistoryForFolder} from './git';
import {execSync} from 'node:child_process';

describe('cleanGitHistoryForFolder', () => {

it('should clean up given folder', () => {
cleanGitHistoryForFolder('tmp');
});

});
19 changes: 19 additions & 0 deletions projects/nx-verdaccio/src/executors/env-teardown/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "TeardownExecutorOptions",
"title": "Environment teardown executor options",
"type": "object",
"properties": {
"environmentRoot": {
"type": "string",
"description": "The root directory of the environment",
"aliases": ["envRoot", "e"]
},
"verbose": {
"type": "boolean",
"description": "Print additional logs"
}
},
"additionalProperties": true,
"required": ["environmentRoot"]
}
5 changes: 5 additions & 0 deletions projects/nx-verdaccio/src/executors/env-teardown/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {Environment} from "../env-bootstrap/npm";

export type TeardownExecutorOptions = Partial<Environment & {
verbose: boolean;
}>;
54 changes: 54 additions & 0 deletions projects/nx-verdaccio/src/executors/env-teardown/teardown-env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {Environment} from "../env-bootstrap/npm";
import {simpleGit, type SimpleGit} from "simple-git";
import {isFolderInRepo} from "./git";
import {ExecutorContext, logger} from "@nx/devkit";
import {runSingleExecutor} from "../../internal/run-executor";
import {join} from "node:path";
import {VERDACCIO_REGISTRY_JSON} from "../env-bootstrap/constants";
import {TARGET_ENVIRONMENT_VERDACCIO_STOP} from "@push-based/nx-verdaccio";
import {fileExists} from "../../internal/file-system";

export const gitClient: SimpleGit = simpleGit(process.cwd());
export type TeardownEnvironmentOptions = Environment & { verbose?: boolean };

export async function teardownEnvironment(
context: ExecutorContext,
options: TeardownEnvironmentOptions,
git: SimpleGit = gitClient
): Promise<void> {
const {verbose, environmentRoot} = options;

// kill verdaccio process if running
const registryJsonExists = await fileExists(join(environmentRoot, VERDACCIO_REGISTRY_JSON));
if (registryJsonExists) {
await runSingleExecutor(
{
project: context.projectName,
target: TARGET_ENVIRONMENT_VERDACCIO_STOP,
},
{
...(verbose ? {verbose} : {}),
filePath: join(environmentRoot, VERDACCIO_REGISTRY_JSON),
},
context
);
} else {
logger.info(`No verdaccio-registry.json file found in ${environmentRoot}.`);
}

// clean environmentRoot

const environmentRootInRepo = await isFolderInRepo(environmentRoot);
if (environmentRootInRepo) {
await git.checkout([environmentRoot]);
logger.info(`Cleaned git history in ${environmentRoot}.`);
} else {
try {

} catch (error) {
// throw new Error(`Error cleaning history of folder ${environmentRoot}. ${error.message}`);
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { describe, expect, it, vi } from 'vitest';
import { teardownEnvironment } from './bootstrap-env';
import * as verdaccioRegistryModule from './verdaccio-registry';
import * as npmModule from './npm';
import * as fs from 'node:fs/promises';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type ExecutorOutput = {
success: boolean;
command?: string;
error?: Error;
};
11 changes: 10 additions & 1 deletion projects/nx-verdaccio/src/internal/file-system.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mkdir } from 'node:fs/promises';
import {mkdir, stat} from 'node:fs/promises';

export async function ensureDirectoryExists(baseDir: string) {
try {
Expand All @@ -11,3 +11,12 @@ export async function ensureDirectoryExists(baseDir: string) {
}
}
}

export async function fileExists(path: string): Promise<boolean> {
try {
const stats = await stat(path);
return stats.isFile();
} catch {
return false;
}
}

0 comments on commit 33b1d3b

Please sign in to comment.