Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add global specification watcher #220

Merged
merged 32 commits into from
Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
58634a9
feat: add global specification watcher
imabp Feb 8, 2022
fdd4413
fix: temporary remove test for watch mode
imabp Feb 9, 2022
300a068
fix:lint
imabp Feb 9, 2022
3ae7505
fix: specfile to file
imabp Feb 9, 2022
24f55c7
fix: edit change message for watcher
imabp Feb 9, 2022
755e1ac
fix: change watch flag description
imabp Feb 9, 2022
3f29110
feat: add watcher in diff
imabp Feb 9, 2022
2458b90
Merge branch 'master' of https://github.com/asyncapi/cli into imabp-w…
imabp Feb 9, 2022
2cf0aa5
fix: refactor watcher configuration
imabp Feb 9, 2022
3f94bc9
fix: code smell
imabp Feb 9, 2022
aa0db23
fix: refactor watch command.
imabp Feb 9, 2022
5cae99b
feat: auto-disable watch mode for web URLs
imabp Feb 10, 2022
bef53f7
Merge branch 'master' into imabp-watch
imabp Feb 10, 2022
71afd18
fix: merge conflicts
imabp Feb 10, 2022
a91f94d
fix: update log messages
imabp Feb 10, 2022
15d58ca
fix: change log color
imabp Feb 10, 2022
89b88a9
fix: make log color private
imabp Feb 10, 2022
87e8023
fix: remove unused red log
imabp Feb 10, 2022
4e88942
fix: disable watch for web urls in validate
imabp Feb 10, 2022
0f791e7
fix: refactor auto-disable log
imabp Feb 11, 2022
4600880
fix: fix multiple watch instances
imabp Feb 11, 2022
8c6cdf9
feat: add conditional logs for watcher
imabp Feb 11, 2022
470fc7d
Remove ConditionalNestedLogs
imabp Feb 14, 2022
056a712
Add conditional log to watch_messages natively.
imabp Feb 14, 2022
e60126e
fix: update function signature
imabp Feb 14, 2022
79580fb
fix: update conditional check for chokidar
imabp Feb 14, 2022
f80690f
feat: Chokidar Instance Store
imabp Feb 15, 2022
7694cf4
fix: use map to store instances.
imabp Feb 16, 2022
84ec9ff
fix: remove start message
imabp Feb 18, 2022
aa42efd
feat: extend support for node versions
imabp Feb 18, 2022
3b5651a
fix: refactor watcher
imabp Feb 19, 2022
64f57d0
Merge branch 'master' into imabp-watch
magicmatatjahu Feb 21, 2022
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
18 changes: 16 additions & 2 deletions src/commands/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
DiffOverrideFileError,
DiffOverrideJSONError,
} from '../errors/diff-error';
import { specWatcher, specWatcherParams } from '../globals';
import { watchFlag } from '../flags';

const { readFile } = fs;

Expand All @@ -36,6 +38,7 @@ export default class Diff extends Command {
char: 'o',
description: 'path to JSON file containing the override properties',
}),
watch: watchFlag
};

static args = [
Expand All @@ -59,11 +62,12 @@ export default class Diff extends Command {
const outputFormat = flags['format'];
const outputType = flags['type'];
const overrideFilePath = flags['overrides'];

const watchMode = flags['watch'];
let firstDocument: Specification, secondDocument: Specification;

try {
firstDocument = await load(firstDocumentPath);
enableWatch(watchMode, { spec: firstDocument, handler: this, handlerName: 'diff', docVersion: 'old', label: 'DIFF_OLD' });
} catch (err) {
if (err instanceof SpecificationFileNotFound) {
this.error(
Expand All @@ -79,6 +83,7 @@ export default class Diff extends Command {

try {
secondDocument = await load(secondDocumentPath);
enableWatch(watchMode, { spec: secondDocument, handler: this, handlerName: 'diff', docVersion: 'new', label: 'DIFF_NEW' });
} catch (err) {
if (err instanceof SpecificationFileNotFound) {
this.error(
Expand Down Expand Up @@ -126,7 +131,6 @@ export default class Diff extends Command {
});
}
}

outputJson(diffOutput: AsyncAPIDiff, outputType: string) {
if (outputType === 'breaking') {
this.log(JSON.stringify(diffOutput.breaking(), null, 2));
Expand Down Expand Up @@ -161,3 +165,13 @@ async function readOverrideFile(path: string): Promise<diff.OverrideObject> {
throw new DiffOverrideJSONError();
}
}
/**
* function to enable watchmode.
* The function is abstracted here, to avoid eslint cognitive complexity error.
*/
const enableWatch = (status: boolean, watcher: specWatcherParams) => {
if (status) {
specWatcher(watcher);
}
};

13 changes: 10 additions & 3 deletions src/commands/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,31 @@ import * as parser from '@asyncapi/parser';
import Command from '../base';
import { ValidationError } from '../errors/validation-error';
import { load } from '../models/SpecificationFile';
import { specWatcher } from '../globals';
import { watchFlag } from '../flags';

export default class Validate extends Command {
static description = 'validate asyncapi file';

static flags = {
help: flags.help({ char: 'h' })
help: flags.help({ char: 'h' }),
watch: watchFlag
}

static args = [
{ name: 'spec-file', description: 'spec path, url, or context-name', required: false },
]

async run() {
const { args } = this.parse(Validate);
const { args, flags } = this.parse(Validate); // NOSONAR
const filePath = args['spec-file'];

const specFile = await load(filePath);
const watchMode = flags['watch'];

const specFile = await load(filePath);
if (watchMode) {
specWatcher({spec: specFile, handler: this, handlerName: 'validate'});
}
try {
if (specFile.getFilePath()) {
await parser.parse(specFile.text());
Expand Down
6 changes: 6 additions & 0 deletions src/flags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { flags } from '@oclif/command';

export const watchFlag = flags.boolean({
imabp marked this conversation as resolved.
Show resolved Hide resolved
char: 'w',
description: 'Enable watch mode'
});
50 changes: 50 additions & 0 deletions src/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import chokidar from 'chokidar';
import chalk from 'chalk';
import Command from './base';
import { Specification } from './models/SpecificationFile';

const GreenLog = chalk.hex('#00FF00');
const OrangeLog = chalk.hex('#FFA500');
const CHOKIDAR_CONFIG = {
// awaitWriteFinish: true // Used for large size specification files.

};
const WATCH_MESSAGES = {
logOnStart: (filePath: string) => console.log(GreenLog(`Watching AsyncAPI file at ${filePath}\n`)),
logOnChange: (handlerName: string) => console.log(OrangeLog(`Change detected, running ${handlerName}\n`)),
logOnAutoDisable: (docVersion: 'old' | 'new' | '' = '') => console.log(OrangeLog(`Watch mode for ${docVersion || 'AsyncAPI'} file was not enabled.`), OrangeLog('\nINFO: Watch works only with files from local file system\n'))
};

const CHOKIDAR_INSTANCE_STORE = new Map<string, boolean>();

export type specWatcherParams = {
spec: Specification,
handler: Command,
handlerName: string,
label?: string,
docVersion?: 'old' | 'new';
}

export const specWatcher = (params: specWatcherParams) => {
if (!params.spec.getFilePath()) { return WATCH_MESSAGES.logOnAutoDisable(params.docVersion); }
if (CHOKIDAR_INSTANCE_STORE.get(params.label || '_default')) { return; }

const filePath = params.spec.getFilePath() as string;
try {
WATCH_MESSAGES.logOnStart(filePath);
chokidar
.watch(filePath, CHOKIDAR_CONFIG)
.on('change', async () => {
WATCH_MESSAGES.logOnChange(params.handlerName);
try {
await params.handler.run();
} catch (err) {
await params.handler.catch(err);
}
});
CHOKIDAR_INSTANCE_STORE.set(params.label || '_default', true);
} catch (error) {
console.log(error);
}
};

1 change: 0 additions & 1 deletion test/commands/validate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import * as path from 'path';
import { expect, test } from '@oclif/test';
import {NO_CONTEXTS_SAVED} from '../../src/errors/context-error';

import TestHelper from '../testHelper';

const testHelper = new TestHelper();
Expand Down