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

Feature/generate on changes #1794

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"cSpell.words": ["listitem", "openapi", "Orval", "Petstore", "tanstack"]
"cSpell.words": ["listitem", "openapi", "Orval", "Petstore", "tanstack"],
"typescript.tsdk": "node_modules/typescript/lib"
}
3 changes: 3 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export type NormalizedOutputOptions = {
urlEncodeParameters: boolean;
unionAddMissingProperties: boolean;
optionsParamRequired: boolean;
onChanges: boolean;
propertySortOrder: PropertySortOrder;
};

Expand Down Expand Up @@ -214,6 +215,7 @@ export type OutputOptions = {
urlEncodeParameters?: boolean;
unionAddMissingProperties?: boolean;
optionsParamRequired?: boolean;
onChanges?: boolean;
propertySortOrder?: PropertySortOrder;
};

Expand Down Expand Up @@ -634,6 +636,7 @@ export interface GlobalOptions {
packageJson?: string;
input?: string;
output?: string;
onChanges?: boolean;
}

export interface Tsconfig {
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/utils/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ export const createSuccessMessage = (backend?: string) =>
}Your OpenAPI spec has been converted into ready to use orval!`,
);

export const nothingChangedMessage = (backend?: string) =>
log(
`🎉 ${
backend ? `${chalk.green(backend)} - ` : ''
}No changes detected, skipping generation`,
);

export const ibmOpenapiValidatorWarnings = (
warnings: {
path: string[];
Expand Down
8 changes: 7 additions & 1 deletion packages/orval/src/bin/orval.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#!/usr/bin/env node
import { isString, logError, startMessage } from '@orval/core';
import { cac } from 'cac';
import { generateConfig, generateSpec } from '../generate';
import pkg from '../../package.json';
import { generateConfig, generateSpec } from '../generate';
import { normalizeOptions } from '../utils/options';
import { startWatcher } from '../utils/watcher';
import { writeLastCommit } from '../utils/write-last-commit';

const cli = cac('orval');

Expand Down Expand Up @@ -40,6 +41,7 @@ cli
.option('--tslint [path]', 'tslint generated files')
.option('--biome [path]', 'biome generated files')
.option('--tsconfig [path]', 'path to your tsconfig file')
.option('--onChanges', 'only generate when the input file changes')
.action(async (paths, cmd) => {
if (!cmd.config && isString(cmd.input) && isString(cmd.output)) {
const normalizedOptions = await normalizeOptions({
Expand All @@ -54,6 +56,7 @@ cli
client: cmd.client,
mode: cmd.mode,
tsconfig: cmd.tsconfig,
onChanges: cmd.onChanges,
},
});

Expand All @@ -63,6 +66,7 @@ cli
async () => {
try {
await generateSpec(process.cwd(), normalizedOptions);
await writeLastCommit(process.cwd());
} catch (e) {
logError(e);
}
Expand All @@ -72,6 +76,7 @@ cli
} else {
try {
await generateSpec(process.cwd(), normalizedOptions);
await writeLastCommit(process.cwd());
} catch (e) {
logError(e);
}
Expand All @@ -90,6 +95,7 @@ cli
tsconfig: cmd.tsconfig,
input: cmd.input,
output: cmd.output,
onChanges: cmd.onChanges,
});
}
});
Expand Down
21 changes: 17 additions & 4 deletions packages/orval/src/generate.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import {
asyncReduce,
ConfigExternal,
upath,
logError,
getFileInfo,
GlobalOptions,
isFunction,
isString,
loadFile,
log,
NormalizedOptions,
logError,
NormalizedConfig,
NormalizedOptions,
nothingChangedMessage,
removeFiles,
upath,
} from '@orval/core';
import { importSpecs } from './import-specs';
import { normalizeOptions } from './utils/options';
import { startWatcher } from './utils/watcher';
import { writeLastCommit } from './utils/write-last-commit';
import { writeSpecs } from './write-specs';

export const generateSpec = async (
Expand Down Expand Up @@ -44,6 +46,12 @@ export const generateSpec = async (
}

const writeSpecBuilder = await importSpecs(workspace, options);

if (!writeSpecBuilder) {
nothingChangedMessage(projectName);
return;
}

await writeSpecs(writeSpecBuilder, workspace, options, projectName);
};

Expand Down Expand Up @@ -85,6 +93,7 @@ export const generateSpecs = async (
);

if (hasErrors) process.exit(1);

return accumulate;
};

Expand Down Expand Up @@ -131,10 +140,14 @@ export const generateConfig = async (
if (options?.watch && fileToWatch.length) {
startWatcher(
options?.watch,
() => generateSpecs(normalizedConfig, workspace, options?.projectName),
async () => {
await generateSpecs(normalizedConfig, workspace, options?.projectName);
await writeLastCommit(workspace);
},
fileToWatch,
);
} else {
await generateSpecs(normalizedConfig, workspace, options?.projectName);
await writeLastCommit(workspace);
}
};
52 changes: 49 additions & 3 deletions packages/orval/src/import-specs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import {
isUrl,
log,
NormalizedOptions,
upath,
SwaggerParserOptions,
upath,
WriteSpecsBuilder,
} from '@orval/core';
import chalk from 'chalk';
import yaml from 'js-yaml';
import { execSync } from 'child_process';
import fs from 'fs-extra';
import yaml from 'js-yaml';

import { importOpenApi } from './import-open-api';
import { getNodeModulesPath } from './utils/node-modules';
import { readLastCommit } from './utils/read-last-commit';

const resolveSpecs = async (
path: string,
Expand Down Expand Up @@ -59,7 +62,7 @@ const resolveSpecs = async (
export const importSpecs = async (
workspace: string,
options: NormalizedOptions,
): Promise<WriteSpecsBuilder> => {
): Promise<WriteSpecsBuilder | undefined> => {
const { input, output } = options;

if (isObject(input.target)) {
Expand All @@ -83,6 +86,49 @@ export const importSpecs = async (
!output.target,
);

if (options.output.onChanges) {
const nodeModulesPath = await getNodeModulesPath(workspace);

if (nodeModulesPath) {
const lastCommit = await readLastCommit(workspace);

if (lastCommit) {
const currentCommit = execSync('git rev-parse HEAD').toString();

if (lastCommit === currentCommit) {
return;
}

const diff = execSync(
`git diff --name-only ${lastCommit} ${currentCommit}`,
).toString();

const trackedFiles = Object.keys(data);

const gitRoot = execSync('git rev-parse --show-toplevel')
.toString()
.replace('\n', '');

const changedFiles = diff
.split('\n')
.filter(Boolean)
.map((path) => {
return upath.joinSafe(gitRoot, path);
});

const hasChangedFiles = changedFiles.some((file) =>
trackedFiles.includes(file),
);

console.log(changedFiles);

if (!hasChangedFiles) {
return;
}
}
}
}

return importOpenApi({
data,
input,
Expand Down
5 changes: 4 additions & 1 deletion packages/orval/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { generateConfig, generateSpec } from './generate';
import { defineConfig, normalizeOptions } from './utils/options';
import { startWatcher } from './utils/watcher';
import { writeLastCommit } from './utils/write-last-commit';

const generate = async (
optionsExport?: string | OptionsExport,
Expand All @@ -30,6 +31,7 @@ const generate = async (
async () => {
try {
await generateSpec(workspace, normalizedOptions);
await writeLastCommit(workspace);
} catch (e) {
logError(e, options?.projectName);
}
Expand All @@ -38,7 +40,8 @@ const generate = async (
);
} else {
try {
return await generateSpec(workspace, normalizedOptions);
await generateSpec(workspace, normalizedOptions);
await writeLastCommit(workspace);
} catch (e) {
logError(e, options?.projectName);
}
Expand Down
8 changes: 8 additions & 0 deletions packages/orval/src/utils/node-modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import findUp from 'find-up';

export const getNodeModulesPath = async (workspace: string) => {
return await findUp(['node_modules'], {
cwd: workspace,
type: 'directory',
});
};
13 changes: 11 additions & 2 deletions packages/orval/src/utils/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,16 @@ export const normalizeOptions = async (
workspace,
);

const { clean, prettier, client, httpClient, mode, tslint, biome } =
globalOptions;
const {
clean,
prettier,
client,
httpClient,
mode,
tslint,
biome,
onChanges,
} = globalOptions;

const tsconfig = await loadTsconfig(
outputOptions.tsconfig || globalOptions.tsconfig,
Expand Down Expand Up @@ -161,6 +169,7 @@ export const normalizeOptions = async (
baseUrl: outputOptions.baseUrl,
unionAddMissingProperties:
outputOptions.unionAddMissingProperties ?? false,
onChanges: outputOptions.onChanges ?? onChanges ?? false,
override: {
...outputOptions.override,
mock: {
Expand Down
14 changes: 14 additions & 0 deletions packages/orval/src/utils/read-last-commit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { upath } from '@orval/core';
import fs from 'fs-extra';
import { getNodeModulesPath } from './node-modules';

export const readLastCommit = async (workspace: string) => {
const nodeModulesPath = await getNodeModulesPath(workspace);

if (!nodeModulesPath) return;

return fs.readFileSync(
upath.join(nodeModulesPath, './.orval/last-commit'),
'utf8',
);
};
15 changes: 15 additions & 0 deletions packages/orval/src/utils/write-last-commit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { upath } from '@orval/core';
import { execSync } from 'child_process';
import fs from 'fs-extra';
import { getNodeModulesPath } from './node-modules';

export const writeLastCommit = async (workspace: string) => {
const nodeModulesPath = await getNodeModulesPath(workspace);

if (!nodeModulesPath) return;

fs.outputFileSync(
upath.join(nodeModulesPath, './.orval/last-commit'),
execSync('git rev-parse HEAD').toString(),
);
};
2 changes: 1 addition & 1 deletion samples/react-query/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"start": "react-scripts start",
"build": "react-scripts build",
"eject": "react-scripts eject",
"generate-api": "node ../../../packages/orval/dist/bin/orval.js",
"generate-api": "node ../../../packages/orval/dist/bin/orval.js --onChanges",
"test": "tsc --noEmit"
},
"eslintConfig": {
Expand Down
Loading
Loading