Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9d91437
feat(backent): adding react-ts template (#56)
Sma1lboy Nov 28, 2024
5bbfdd9
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Nov 28, 2024
bfda89c
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Nov 28, 2024
da9ef45
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Nov 29, 2024
ec2bb50
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Nov 30, 2024
5bdd162
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Dec 13, 2024
2c9ae0f
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Dec 13, 2024
60a3098
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Dec 15, 2024
a923bc5
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Dec 15, 2024
fd2c639
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Dec 16, 2024
66137f1
Merge branch 'main' of https://github.com/Sma1lboy/GeneratorAI
ZHallen122 Dec 17, 2024
20db596
copy project template under projects
ZHallen122 Dec 17, 2024
7164ff7
move rootpath into current workspace root
ZHallen122 Dec 17, 2024
0213cff
remove log
ZHallen122 Dec 17, 2024
595a868
refactor(tests): use getTemplatePath for template directory in copyPr…
Sma1lboy Dec 17, 2024
6f4dbd1
Merge branch 'feat_backend_copy_project_template' of https://github.c…
ZHallen122 Dec 17, 2024
10172d9
merge
ZHallen122 Dec 17, 2024
b40fb98
add copy template to project init
ZHallen122 Dec 17, 2024
8c9a032
update path import
ZHallen122 Dec 17, 2024
b3846d1
change copy template order
ZHallen122 Dec 17, 2024
ba15953
add logger, and remove copy template
ZHallen122 Dec 17, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { copyProjectTemplate } from 'src/build-system/utils/files';
import { promises as fs } from 'fs';
import { v4 as uuidv4 } from 'uuid';
import { getTemplatePath } from 'src/config/common-path';
import { Logger } from '@nestjs/common';

describe('Copy Project Template', () => {
it('should copy the template to the specified UUID folder', async () => {
const templatePath = getTemplatePath('template-backend');
const projectUUID = uuidv4();

Logger.log('template-path:', templatePath);
const projectPath = await copyProjectTemplate(templatePath, projectUUID);
expect(await fs.access(projectPath)).toBeUndefined(); // Project folder exists
await fs.rm(projectPath, { recursive: true, force: true });
});
});
Comment on lines +7 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance test coverage with additional test cases.

The current test suite only covers the happy path. Consider adding test cases for:

  • Invalid template paths
  • File system permission errors
  • Template content validation

Here's a suggested enhancement:

 describe('Copy Project Template', () => {
+  let projectPath: string;
+
+  afterEach(async () => {
+    if (projectPath) {
+      await fs.rm(projectPath, { recursive: true, force: true });
+    }
+  });
+
   it('should copy the template to the specified UUID folder', async () => {
     const templatePath = getTemplatePath('template-backend');
     const projectUUID = uuidv4();
-    Logger.log('template-path:', templatePath);
-    const projectPath = await copyProjectTemplate(templatePath, projectUUID);
+    projectPath = await copyProjectTemplate(templatePath, projectUUID);
     expect(await fs.access(projectPath)).toBeUndefined(); // Project folder exists
-    await fs.rm(projectPath, { recursive: true, force: true });
+    
+    // Validate template content
+    const files = await fs.readdir(projectPath);
+    expect(files.length).toBeGreaterThan(0);
   });
+
+  it('should throw error for invalid template path', async () => {
+    const invalidPath = '/invalid/path';
+    const projectUUID = uuidv4();
+    
+    await expect(copyProjectTemplate(invalidPath, projectUUID))
+      .rejects
+      .toThrow('Template path does not exist');
+  });
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
describe('Copy Project Template', () => {
it('should copy the template to the specified UUID folder', async () => {
const templatePath = getTemplatePath('template-backend');
const projectUUID = uuidv4();
Logger.log('template-path:', templatePath);
const projectPath = await copyProjectTemplate(templatePath, projectUUID);
expect(await fs.access(projectPath)).toBeUndefined(); // Project folder exists
await fs.rm(projectPath, { recursive: true, force: true });
});
});
describe('Copy Project Template', () => {
let projectPath: string;
afterEach(async () => {
if (projectPath) {
await fs.rm(projectPath, { recursive: true, force: true });
}
});
it('should copy the template to the specified UUID folder', async () => {
const templatePath = getTemplatePath('template-backend');
const projectUUID = uuidv4();
projectPath = await copyProjectTemplate(templatePath, projectUUID);
expect(await fs.access(projectPath)).toBeUndefined(); // Project folder exists
// Validate template content
const files = await fs.readdir(projectPath);
expect(files.length).toBeGreaterThan(0);
});
it('should throw error for invalid template path', async () => {
const invalidPath = '/invalid/path';
const projectUUID = uuidv4();
await expect(copyProjectTemplate(invalidPath, projectUUID))
.rejects
.toThrow('Template path does not exist');
});
});

6 changes: 5 additions & 1 deletion backend/src/build-system/handlers/project-init.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { BuilderContext } from '../context';
import { BuildHandlerManager } from '../hanlder-manager';
import { BuildHandler, BuildResult } from '../types';
import { Logger } from '@nestjs/common';

export class ProjectInitHandler implements BuildHandler {
readonly id = 'op:PROJECT::STATE:SETUP';
private readonly logger = new Logger('ProjectInitHandler');

async run(context: BuilderContext): Promise<BuildResult> {
console.log('Setting up project...');
this.logger.log('Setting up project...');

const result = {
projectName: 'online shoping',
descreption: 'sell products',
Platform: 'Web',
path: '/path/to/project',
};
context.setGlobalContext('projectConfig', result);
Comment on lines +12 to 19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Update hardcoded project configuration.

The result object contains hardcoded values and a typo in 'descreption'. Consider:

  1. Using dynamic values from context or parameters
  2. Including the created project paths
  3. Fixing the typo in 'description'

Here's a suggested fix:

     const result = {
-      projectName: 'online shoping',
-      descreption: 'sell products',
-      Platform: 'Web',
-      path: '/path/to/project',
+      projectName: context.getConfig('projectName'),
+      description: context.getConfig('description'),
+      platform: context.getConfig('platform'),
+      backendPath: backendProjectPath,
     };

Committable suggestion skipped: line range outside the PR's diff.


return {
success: true,
data: result,
Expand Down
42 changes: 41 additions & 1 deletion backend/src/build-system/utils/files.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Logger } from '@nestjs/common';
import fs from 'fs-extra';
import * as fs from 'fs-extra';
import { getProjectPath } from 'src/config/common-path';

const logger = new Logger('file-utils');
/**
Expand All @@ -24,3 +25,42 @@ export async function saveGeneratedCode(
throw error;
}
}

/**
* Copies a project template to a specific location under a given UUID folder.
*
* @param templatePath - The path to the project template containing files.
* @param projectUUID - The UUID of the project folder.
* @returns The path to the copied project directory.
*/
export async function copyProjectTemplate(
templatePath: string,
projectUUID: string,
): Promise<string> {
Comment on lines +36 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add UUID format validation.

The function should validate the projectUUID format before using it to create paths.

Add validation at the start of the function:

 export async function copyProjectTemplate(
   templatePath: string,
   projectUUID: string,
 ): Promise<string> {
+  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
+  if (!uuidRegex.test(projectUUID)) {
+    throw new Error('Invalid UUID format');
+  }
   try {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function copyProjectTemplate(
templatePath: string,
projectUUID: string,
): Promise<string> {
export async function copyProjectTemplate(
templatePath: string,
projectUUID: string,
): Promise<string> {
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
if (!uuidRegex.test(projectUUID)) {
throw new Error('Invalid UUID format');
}

try {
// Validate the template path
const templateExists = await fs
.access(templatePath)
.then(() => true)
.catch(() => false);
if (!templateExists) {
throw new Error(`Template path does not exist: ${templatePath}`);
}

// Resolve the destination path and ensure path exist
const destinationPath = getProjectPath(projectUUID);

// Copy the template to the destination
logger.log(
`Copying template from ${templatePath} to ${destinationPath}...`,
);
await fs.copy(templatePath, destinationPath);

// Return the destination path
logger.log(`Template copied successfully to ${destinationPath}`);
return destinationPath;
} catch (error) {
logger.error('Error copying project template:', error);
throw error;
}
}
9 changes: 6 additions & 3 deletions backend/src/config/common-path.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import * as path from 'path';
import * as os from 'os';
import { existsSync, mkdirSync, promises } from 'fs-extra';
import { createHash } from 'crypto';

// Constants for base directories
const APP_NAME = 'codefox';
const ROOT_DIR = path.join(os.homedir(), `.${APP_NAME}`);
// TODO: hack way to get the root directory of the workspace
const WORKSPACE_ROOT = path.resolve(__dirname, '../../../');
const ROOT_DIR = path.join(WORKSPACE_ROOT, `.${APP_NAME}`);
Comment on lines +6 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve workspace root resolution implementation

The current implementation has several concerns:

  1. The TODO comment indicates this is a temporary solution without explaining why or providing a better alternative
  2. Using __dirname with relative path navigation (../../../) is fragile and could break if the directory structure changes
  3. No validation is performed to ensure the resolved workspace root is valid

Consider:

  1. Using environment variables or configuration files to define the workspace root
  2. Adding validation to ensure the resolved path exists and has the expected structure
  3. Documenting the rationale behind the current approach and the intended permanent solution
-// TODO: hack way to get the root directory of the workspace
-const WORKSPACE_ROOT = path.resolve(__dirname, '../../../');
+// TODO(high): Replace with configuration-based workspace root resolution
+// Current limitation: Using relative path resolution which is fragile
+const WORKSPACE_ROOT = process.env.WORKSPACE_ROOT || path.resolve(__dirname, '../../../');
+if (!existsSync(WORKSPACE_ROOT)) {
+  throw new Error(`Invalid workspace root: ${WORKSPACE_ROOT}`);
+}

Committable suggestion skipped: line range outside the PR's diff.


export const TEMPLATE_PATH = path.join(WORKSPACE_ROOT, 'backend/template');
export const getTemplatePath = (templateName: string): string =>
path.join(TEMPLATE_PATH, templateName);
// Utility function to ensure a directory exists
const ensureDir = (dirPath: string): string => {
if (!existsSync(dirPath)) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/config/common-path.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import path from 'path';
import * as path from 'path';
import { existsSync, mkdirSync, promises as fsPromises } from 'fs-extra';
import { createHash } from 'crypto';

Expand Down
Loading