Skip to content

Commit aabb899

Browse files
committed
fix(nx-plugin): improve logging and ensure unique temporary directories in update-api executor
1 parent 59fe9e4 commit aabb899

File tree

3 files changed

+106
-7
lines changed

3 files changed

+106
-7
lines changed

packages/nx-plugin/src/executors/update-api/index.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const tempDirectory = `temp-update-api-${randomUUID()}`;
3737
const defaultOptions: UpdateApiExecutorSchema = {
3838
client: TestOptions.client,
3939
// don't use tmp, as it is used internally in the lib code for temp files
40-
directory: 'temp-update-api',
40+
directory: tempDirectory,
4141
name: TestOptions.name,
4242
plugins: [],
4343
scope: TestOptions.scope,

packages/nx-plugin/src/executors/update-api/index.ts

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,49 +21,87 @@ async function setup({
2121
options: UpdateApiExecutorSchema;
2222
tempFolder: string;
2323
}) {
24+
logger.debug(
25+
`Setting up update-api executor with options: ${JSON.stringify(options, null, 2)}`,
26+
);
27+
logger.debug(`Using temp folder: ${tempFolder}`);
28+
logger.debug(`Absolute temp folder path: ${absoluteTempFolder}`);
29+
2430
const tempApiFolder = join(tempFolder, CONSTANTS.SPEC_DIR_NAME);
31+
logger.debug(`Temp API folder path: ${tempApiFolder}`);
2532

2633
// Create temp folders if they don't exist
2734
const absoluteTempApiFolder = join(
2835
absoluteTempFolder,
2936
CONSTANTS.SPEC_DIR_NAME,
3037
);
38+
logger.debug(`Absolute temp API folder path: ${absoluteTempApiFolder}`);
39+
3140
if (!existsSync(absoluteTempApiFolder)) {
3241
logger.debug(`Creating executor temp api folder: ${absoluteTempApiFolder}`);
3342
await mkdir(absoluteTempApiFolder, { recursive: true });
43+
logger.debug(`Created temp API folder: ${absoluteTempApiFolder}`);
44+
} else {
45+
logger.debug(`Temp API folder already exists: ${absoluteTempApiFolder}`);
3446
}
3547
logger.debug('Temp folders created.');
3648

3749
// Determine file paths
3850
const projectRoot = join(options.directory, options.name);
51+
logger.debug(`Project root path: ${projectRoot}`);
52+
3953
const apiDirectory = join(projectRoot, CONSTANTS.SPEC_DIR_NAME);
54+
logger.debug(`API directory path: ${apiDirectory}`);
55+
4056
const existingSpecPath = join(apiDirectory, CONSTANTS.SPEC_FILE_NAME);
57+
logger.debug(`Existing spec file path: ${existingSpecPath}`);
58+
4159
const tempSpecPath = join(tempApiFolder, CONSTANTS.SPEC_FILE_NAME);
60+
logger.debug(`Temp spec file path: ${tempSpecPath}`);
61+
4262
const generatedTempDir = join(tempFolder, CONSTANTS.GENERATED_DIR_NAME);
63+
logger.debug(`Generated temp directory path: ${generatedTempDir}`);
4364

4465
// Check if existing spec exists
4566
const absoluteExistingSpecPath = join(process.cwd(), existingSpecPath);
67+
logger.debug(`Absolute existing spec path: ${absoluteExistingSpecPath}`);
68+
4669
if (!existsSync(absoluteExistingSpecPath)) {
70+
logger.error(`No existing spec file found at ${existingSpecPath}.`);
4771
throw new Error(`No existing spec file found at ${existingSpecPath}.`);
72+
} else {
73+
logger.debug(`Existing spec file found at ${absoluteExistingSpecPath}`);
4874
}
4975

76+
logger.info(`Bundling and dereferencing spec file from: ${options.spec}`);
5077
const dereferencedSpec = await bundleAndDereferenceSpecFile({
5178
client: options.client,
5279
outputPath: tempSpecPath,
5380
plugins: options.plugins,
5481
specPath: options.spec,
5582
});
83+
logger.info(`Spec file bundled successfully`);
84+
5685
// save the dereferenced spec to the temp spec file
5786
try {
87+
logger.debug(`Writing dereferenced spec to temp file: ${tempSpecPath}`);
5888
writeFileSync(tempSpecPath, JSON.stringify(dereferencedSpec, null, 2));
89+
logger.debug(`Dereferenced spec written to temp file successfully`);
5990
} catch (error) {
6091
logger.error(`Failed to write dereferenced spec to temp file: ${error}.`);
6192
throw error;
6293
}
6394

6495
logger.info('Reading existing and new spec files...');
6596
const absoluteTempSpecPath = join(process.cwd(), tempSpecPath);
97+
logger.debug(`Absolute temp spec path: ${absoluteTempSpecPath}`);
98+
99+
logger.debug(`Reading new spec file from: ${absoluteTempSpecPath}`);
66100
const newSpecString = await readFile(absoluteTempSpecPath, 'utf-8');
101+
logger.debug(
102+
`New spec file read successfully, size: ${newSpecString.length} bytes`,
103+
);
104+
67105
if (!newSpecString) {
68106
logger.error('New spec file is empty.');
69107
throw new Error('New spec file is empty.');
@@ -90,11 +128,21 @@ const runExecutor: PromiseExecutor<UpdateApiExecutorSchema> = async (
90128
// eslint-disable-next-line @typescript-eslint/no-unused-vars
91129
_context,
92130
) => {
131+
logger.info(
132+
`Starting update-api executor with options: ${JSON.stringify(options, null, 2)}`,
133+
);
134+
93135
const tempFolder = options.tempFolder ?? CONSTANTS.TMP_DIR_NAME;
136+
logger.debug(`Using temp folder: ${tempFolder}`);
137+
94138
const absoluteTempFolder = join(process.cwd(), tempFolder);
139+
logger.debug(`Absolute temp folder path: ${absoluteTempFolder}`);
140+
95141
const force = options.force ?? false;
142+
logger.debug(`Force flag: ${force}`);
96143

97144
try {
145+
logger.info(`Setting up executor environment...`);
98146
const {
99147
absoluteExistingSpecPath,
100148
absoluteTempSpecPath,
@@ -108,15 +156,20 @@ const runExecutor: PromiseExecutor<UpdateApiExecutorSchema> = async (
108156
options,
109157
tempFolder,
110158
});
159+
logger.info(`Setup completed successfully`);
160+
161+
logger.info(`Comparing existing spec with new spec...`);
111162
const areSpecsEqual = await compareSpecs(
112163
absoluteExistingSpecPath,
113164
absoluteTempSpecPath,
114165
);
166+
logger.debug(`Specs comparison result - equal: ${areSpecsEqual}`);
115167

116168
// If specs are equal, we don't need to generate new client code and we can return unless the force flag is true
117169
if (areSpecsEqual) {
118170
logger.info('No changes detected in the API spec.');
119171
if (!force) {
172+
logger.info('Force flag is false. Skipping client code generation.');
120173
await cleanup(absoluteTempFolder);
121174
return { success: true };
122175
} else {
@@ -131,32 +184,54 @@ const runExecutor: PromiseExecutor<UpdateApiExecutorSchema> = async (
131184
// Generate new client code in temp directory
132185
// Create temp generated directory
133186
const absoluteGeneratedTempDir = join(process.cwd(), generatedTempDir);
187+
logger.debug(
188+
`Absolute generated temp directory: ${absoluteGeneratedTempDir}`,
189+
);
190+
134191
if (!existsSync(absoluteGeneratedTempDir)) {
192+
logger.debug(
193+
`Creating temp generated directory: ${absoluteGeneratedTempDir}`,
194+
);
135195
await mkdir(absoluteGeneratedTempDir);
196+
logger.debug(`Created temp generated directory successfully`);
197+
} else {
198+
logger.debug(`Temp generated directory already exists`);
136199
}
137200

138201
// Generate new client code
202+
logger.info(
203+
`Generating client code using client: ${options.client} and plugins: ${options.plugins.join(', ')}`,
204+
);
139205
await generateClientCode({
140206
clientType: options.client,
141207
outputPath: generatedTempDir,
142208
plugins: options.plugins,
143209
specFile: tempSpecPath,
144210
});
211+
logger.info(`Client code generated successfully`);
145212

146213
// After successful generation, update the files
147214
logger.info('Updating existing spec and client files...');
148215

149216
const absoluteApiDirectory = join(process.cwd(), apiDirectory);
217+
logger.debug(`Absolute API directory: ${absoluteApiDirectory}`);
218+
150219
const apiDirectoryExists = existsSync(absoluteApiDirectory);
220+
logger.debug(`API directory exists: ${apiDirectoryExists}`);
221+
151222
const existingSpecFileExists = existsSync(absoluteExistingSpecPath);
223+
logger.debug(`Existing spec file exists: ${existingSpecFileExists}`);
224+
152225
// Copy new spec to project
153226
if (apiDirectoryExists) {
154227
if (existingSpecFileExists) {
155228
logger.debug('Existing spec file found. Updating...');
156229
} else {
157230
logger.debug('No existing spec file found. Creating...');
158231
}
232+
logger.debug(`Writing new spec to: ${absoluteExistingSpecPath}`);
159233
writeFileSync(absoluteExistingSpecPath, newSpecString);
234+
logger.debug(`Spec file updated successfully`);
160235
} else {
161236
logger.error(
162237
`No API directory found at ${apiDirectory} after checking once, exiting.`,
@@ -171,42 +246,65 @@ const runExecutor: PromiseExecutor<UpdateApiExecutorSchema> = async (
171246
'src',
172247
CONSTANTS.GENERATED_DIR_NAME,
173248
);
249+
logger.debug(`Project generated directory: ${projectGeneratedDir}`);
174250

175251
const absoluteProjectGeneratedDir = join(
176252
process.cwd(),
177253
projectGeneratedDir,
178254
);
255+
logger.debug(
256+
`Absolute project generated directory: ${absoluteProjectGeneratedDir}`,
257+
);
179258

180259
// Remove old generated directory if it exists
181260
if (existsSync(absoluteProjectGeneratedDir)) {
261+
logger.debug(
262+
`Removing old generated directory: ${absoluteProjectGeneratedDir}`,
263+
);
182264
await rm(absoluteProjectGeneratedDir, {
183265
force: true,
184266
recursive: true,
185267
});
268+
logger.debug(`Old generated directory removed successfully`);
269+
} else {
270+
logger.debug(`No existing generated directory to remove`);
186271
}
187272

188273
// Copy new generated directory
274+
logger.debug(
275+
`Copying from ${absoluteGeneratedTempDir} to ${absoluteProjectGeneratedDir}`,
276+
);
189277
await cp(absoluteGeneratedTempDir, absoluteProjectGeneratedDir, {
190278
recursive: true,
191279
});
280+
logger.debug(`Generated files copied successfully`);
192281

193282
logger.info('Successfully updated API client and spec files.');
283+
logger.debug(`Cleaning up temp folder: ${absoluteTempFolder}`);
194284
await cleanup(absoluteTempFolder);
285+
logger.info('Update-api executor completed successfully');
195286
return { success: true };
196287
} catch (error) {
197-
logger.error(
198-
`Failed to update API: ${error instanceof Error ? error.message : String(error)}.`,
199-
);
288+
const errorMessage = error instanceof Error ? error.message : String(error);
289+
logger.error(`Failed to update API: ${errorMessage}`);
290+
logger.debug(`Error details: ${error}`);
291+
logger.debug(`Cleaning up temp folder after error: ${absoluteTempFolder}`);
200292
await cleanup(absoluteTempFolder);
201293
return { success: false };
202294
}
203295
};
204296

205297
async function cleanup(tempFolder: string) {
298+
logger.debug(`Cleaning up temp folder: ${tempFolder}`);
206299
const absoluteTempFolder = join(process.cwd(), tempFolder);
300+
logger.debug(`Absolute temp folder path for cleanup: ${absoluteTempFolder}`);
301+
207302
if (existsSync(absoluteTempFolder)) {
208303
logger.debug(`Removing temp folder: ${absoluteTempFolder}`);
209304
await rm(absoluteTempFolder, { force: true, recursive: true });
305+
logger.debug(`Temp folder removed successfully`);
306+
} else {
307+
logger.debug(`Temp folder doesn't exist, nothing to clean up`);
210308
}
211309
}
212310

packages/nx-plugin/src/generators/openapi-client/index.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,19 @@ describe('openapi-client generator', () => {
6767

6868
describe('normalizeOptions', () => {
6969
it('should normalize options with default values', async () => {
70+
const uuid = randomUUID();
7071
const { options, specPath } = await getGeneratorOptions({
71-
name: `test-api-${randomUUID()}`,
72+
name: `test-api-${uuid}`,
7273
tempDirectory,
7374
});
7475
const normalized = normalizeOptions(options);
7576

7677
expect(normalized).toEqual({
7778
clientType: '@hey-api/client-fetch',
7879
plugins: [],
79-
projectDirectory: `${tempDirectory}/test-api-1`,
80+
projectDirectory: `${tempDirectory}/test-api-${uuid}`,
8081
projectName: 'test-api',
81-
projectRoot: `${tempDirectory}/test-api-1/test-api`,
82+
projectRoot: `${tempDirectory}/test-api-${uuid}/test-api`,
8283
projectScope: '@test-api',
8384
specFile: specPath,
8485
tagArray: ['api', 'openapi'],

0 commit comments

Comments
 (0)