Skip to content

Add automation for software engineering process #541

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

Closed
wants to merge 1 commit into from
Closed
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
84 changes: 83 additions & 1 deletion apps/backend/src/api/routes/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import { getCookieUrlFromDomain } from '@gitroom/helpers/subdomain/subdomain.man
import { EmailService } from '@gitroom/nestjs-libraries/services/email.service';
import { RealIP } from 'nestjs-real-ip';
import { UserAgent } from '@gitroom/nestjs-libraries/user/user.agent';
import { ProjectManagementService } from '@gitroom/backend/services/project-management/project-management.service';

@ApiTags('Auth')
@Controller('/auth')
export class AuthController {
constructor(
private _authService: AuthService,
private _emailService: EmailService
private _emailService: EmailService,
private _projectManagementService: ProjectManagementService
) {}
@Post('/register')
async register(
Expand Down Expand Up @@ -207,4 +209,84 @@ export class AuthController {
login: true,
});
}

@Post('/project-management/create-roadmap')
async createRoadmap(
@Body() body: { title: string; description: string },
@Res() response: Response
) {
try {
const roadmap = await this._projectManagementService.createRoadmap(
body.title,
body.description
);
response.status(201).json(roadmap);
} catch (e) {
response.status(400).send(e.message);
}
}

@Post('/project-management/create-user-story')
async createUserStory(
@Body() body: { roadmapId: string; title: string; description: string },
@Res() response: Response
) {
try {
const userStory = await this._projectManagementService.createUserStory(
body.roadmapId,
body.title,
body.description
);
response.status(201).json(userStory);
} catch (e) {
response.status(400).send(e.message);
}
}

@Post('/project-management/create-task')
async createTask(
@Body() body: { userStoryId: string; title: string; description: string },
@Res() response: Response
) {
try {
const task = await this._projectManagementService.createTask(
body.userStoryId,
body.title,
body.description
);
response.status(201).json(task);
} catch (e) {
response.status(400).send(e.message);
}
}
Comment on lines +215 to +261
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation to project management methods

The methods accepting input (createRoadmap, createUserStory, createTask) should validate the incoming data to prevent invalid or malicious input.

Define DTOs with validation decorators:

import { IsString, IsNotEmpty } from 'class-validator';

export class CreateRoadmapDto {
  @IsString()
  @IsNotEmpty()
  title: string;

  @IsString()
  description: string;
}

Update your method to use the DTO:

@Post('/project-management/create-roadmap')
async createRoadmap(
  @Body() body: CreateRoadmapDto,
  @Res() response: Response
) { /* ... */ }


@Get('/project-management/track-progress')
async trackProgress(@Res() response: Response) {
try {
const progress = await this._projectManagementService.trackProgress();
response.status(200).json(progress);
} catch (e) {
response.status(400).send(e.message);
}
}

@Get('/project-management/estimate-timelines')
async estimateTimelines(@Res() response: Response) {
try {
const timelines = await this._projectManagementService.estimateTimelines();
response.status(200).json(timelines);
} catch (e) {
response.status(400).send(e.message);
}
}

@Get('/project-management/identify-roadblocks')
async identifyRoadblocks(@Res() response: Response) {
try {
const roadblocks = await this._projectManagementService.identifyRoadblocks();
response.status(200).json(roadblocks);
} catch (e) {
response.status(400).send(e.message);
}
}
Comment on lines +213 to +291
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing authentication and authorization on project management endpoints

The newly added project management endpoints (createRoadmap, createUserStory, createTask, trackProgress, estimateTimelines, identifyRoadblocks) do not include any authentication or authorization checks. This could allow unauthorized users to access or manipulate project data.

Consider using guards or decorators to enforce authentication:

@UseGuards(AuthGuard('jwt'))
@Post('/project-management/create-roadmap')
async createRoadmap(/* ... */) { /* ... */ }

}
68 changes: 66 additions & 2 deletions apps/backend/src/api/routes/copilot.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Logger, Controller, Get, Post, Req, Res } from '@nestjs/common';
import { Logger, Controller, Get, Post, Req, Res, Body } from '@nestjs/common';
import {
CopilotRuntime,
OpenAIAdapter,
Expand All @@ -7,10 +7,17 @@ import {
import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request';
import { Organization } from '@prisma/client';
import { SubscriptionService } from '@gitroom/nestjs-libraries/database/prisma/subscriptions/subscription.service';
import { CommunicationService } from '@gitroom/backend/services/communication/communication.service';
import { DocumentationService } from '@gitroom/backend/services/documentation/documentation.service';

@Controller('/copilot')
export class CopilotController {
constructor(private _subscriptionService: SubscriptionService) {}
constructor(
private _subscriptionService: SubscriptionService,
private _communicationService: CommunicationService,
private _documentationService: DocumentationService
) {}

@Post('/chat')
chat(@Req() req: Request, @Res() res: Response) {
if (process.env.OPENAI_API_KEY === undefined || process.env.OPENAI_API_KEY === '') {
Expand Down Expand Up @@ -39,4 +46,61 @@ export class CopilotController {
calculateCredits(@GetOrgFromRequest() organization: Organization) {
return this._subscriptionService.checkCredits(organization);
}

@Post('/communicate')
async facilitateCommunication(
@Body() body: { message: string; recipients: string[] },
@Res() response: Response
) {
try {
const result = await this._communicationService.sendMessage(
body.message,
body.recipients
);
response.status(200).json(result);
} catch (e) {
response.status(400).send(e.message);
}
}

@Post('/generate-documentation')
async generateDocumentation(
@Body() body: { projectId: string },
@Res() response: Response
) {
try {
const documentation = await this._documentationService.generateDocumentation(
body.projectId
);
response.status(200).json(documentation);
} catch (e) {
response.status(400).send(e.message);
}
}

@Post('/integrate-slack')
async integrateSlack(
@Body() body: { slackToken: string },
@Res() response: Response
) {
try {
const result = await this._communicationService.integrateSlack(body.slackToken);
response.status(200).json(result);
} catch (e) {
response.status(400).send(e.message);
}
}

@Post('/integrate-teams')
async integrateTeams(
@Body() body: { teamsToken: string },
@Res() response: Response
) {
try {
const result = await this._communicationService.integrateTeams(body.teamsToken);
response.status(200).json(result);
} catch (e) {
response.status(400).send(e.message);
}
}
Comment on lines +81 to +105
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Security concern: Avoid passing tokens directly in request bodies

Passing sensitive tokens like slackToken and teamsToken in the request body can expose them to security risks. Consider implementing OAuth or secure credential storage mechanisms to handle integrations securely.

}
52 changes: 38 additions & 14 deletions apps/backend/src/api/routes/integrations.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class IntegrationsController {
private _integrationManager: IntegrationManager,
private _integrationService: IntegrationService,
private _postService: PostsService
) {}
) { }
@Get('/')
getIntegration() {
return this._integrationManager.getAllIntegrations();
Expand Down Expand Up @@ -147,18 +147,18 @@ export class IntegrationsController {

const { url } = manager.changeProfilePicture
? await manager.changeProfilePicture(
integration.internalId,
integration.token,
body.picture
)
integration.internalId,
integration.token,
body.picture
)
: { url: '' };

const { name } = manager.changeNickname
? await manager.changeNickname(
integration.internalId,
integration.token,
body.name
)
integration.internalId,
integration.token,
body.name
)
: { name: '' };

return this._integrationService.updateNameAndUrl(id, name, url);
Expand Down Expand Up @@ -204,9 +204,9 @@ export class IntegrationsController {
try {
const getExternalUrl = integrationProvider.externalUrl
? {
...(await integrationProvider.externalUrl(externalUrl)),
instanceUrl: externalUrl,
}
...(await integrationProvider.externalUrl(externalUrl)),
instanceUrl: externalUrl,
}
: undefined;

const { codeVerifier, state, url } =
Expand Down Expand Up @@ -506,10 +506,10 @@ export class IntegrationsController {
details
? AuthService.fixedEncryption(details)
: integrationProvider.customFields
? AuthService.fixedEncryption(
? AuthService.fixedEncryption(
Buffer.from(body.code, 'base64').toString()
)
: undefined
: undefined
);
}

Expand Down Expand Up @@ -609,4 +609,28 @@ export class IntegrationsController {
) {
return this._integrationService.changePlugActivation(org.id, id, status);
}

@Post('/deploy')
async deployToEnvironment(
@GetOrgFromRequest() org: Organization,
@Body() body: { environment: string }
) {
// Add logic to automate deployment to various environments
return this._integrationService.deployToEnvironment(org.id, body.environment);
}
Comment on lines +613 to +620
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Review comment is valid and critical

The deployment endpoint lacks essential security measures and implementation:

  • No environment validation exists in the codebase
  • The service method deployToEnvironment is not implemented
  • No authorization checks are present
  • No error handling is implemented

The original review comment correctly identifies critical security concerns that need to be addressed before this endpoint can be safely used.

🔗 Analysis chain

Add input validation and error handling for deployment endpoint

The deployment endpoint needs additional security measures:

  1. Validate the environment string against allowed values
  2. Add error handling for deployment failures
  3. Consider adding role-based access control for deployment operations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if deployment-related permissions are implemented
ast-grep --pattern 'class $_ implements $_ {
  $$$
  @CheckPolicies([AuthorizationActions.$_, Sections.$_])
  $$$
  deployToEnvironment($$$) {
    $$$
  }
  $$$
}'

Length of output: 165


Script:

#!/bin/bash
# Check for any decorators in integrations controller
echo "=== Checking decorators ==="
ast-grep --pattern '@$_($$$)
$$$' apps/backend/src/api/routes/integrations.controller.ts

# Look for environment validation
echo "=== Checking environment validation ==="
rg -A 5 "environment.*validation|validateEnvironment" apps/backend/src/api

# Check integration service implementation
echo "=== Checking integration service ==="
fd "integration.service" --type f --exec cat {}

Length of output: 17975


Script:

#!/bin/bash
# Search for environment-related types or enums
echo "=== Checking environment types ==="
rg -g "*.ts" "enum.*Environment|type.*Environment|interface.*Environment" 

# Search for environment constants
echo "=== Checking environment constants ==="
rg -g "*.ts" "const.*Environment.*=|export.*Environment.*="

# Check for any existing deployment-related code
echo "=== Checking deployment patterns ==="
rg -g "*.ts" "deploy.*environment|environment.*deploy" -A 3

Length of output: 906


@Get('/monitor-performance')
async monitorSystemPerformance(@GetOrgFromRequest() org: Organization) {
// Add logic to monitor system performance and identify potential issues
return this._integrationService.monitorSystemPerformance(org.id);
}
Comment on lines +622 to +626
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Implement rate limiting for performance monitoring endpoint

The performance monitoring endpoint should:

  1. Implement rate limiting to prevent DoS
  2. Define specific metrics to be monitored
  3. Add caching for performance data
  @Get('/monitor-performance')
+ @UseInterceptors(RateLimitInterceptor)
  async monitorSystemPerformance(@GetOrgFromRequest() org: Organization) {
-   // Add logic to monitor system performance and identify potential issues
-   return this._integrationService.monitorSystemPerformance(org.id);
+   const cacheKey = `performance:${org.id}`;
+   const cached = await this.cacheManager.get(cacheKey);
+   if (cached) return cached;
+   
+   const metrics = await this._integrationService.monitorSystemPerformance(org.id);
+   await this.cacheManager.set(cacheKey, metrics, 300);
+   return metrics;
  }

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


@Post('/bug-fix')
async automateBugFixes(
@GetOrgFromRequest() org: Organization,
@Body() body: { feedback: string }
) {
// Add logic to automate bug fixes and updates based on user feedback and system logs
return this._integrationService.automateBugFixes(org.id, body.feedback);
}
Comment on lines +628 to +635
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add validation and sanitization for bug fix automation endpoint

The bug fix automation endpoint needs:

  1. Input validation for feedback
  2. Rate limiting for submissions
  3. Logging of automation attempts
  4. Clear documentation of the expected feedback format
  @Post('/bug-fix')
+ @UseInterceptors(RateLimitInterceptor)
  async automateBugFixes(
    @GetOrgFromRequest() org: Organization,
-   @Body() body: { feedback: string }
+   @Body() body: AutomateBugFixDto
  ) {
-   // Add logic to automate bug fixes and updates based on user feedback and system logs
+   this.logger.info(`Automating bug fix for org ${org.id} with feedback: ${body.feedback}`);
+   try {
+     return await this._integrationService.automateBugFixes(org.id, body.feedback);
+   } catch (error) {
+     this.logger.error(`Bug fix automation failed: ${error.message}`);
+     throw new InternalServerErrorException('Failed to automate bug fix');
+   }
  }

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

}
36 changes: 35 additions & 1 deletion apps/backend/src/api/routes/posts.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import { CreateGeneratedPostsDto } from '@gitroom/nestjs-libraries/dtos/generato
import { AgentGraphService } from '@gitroom/nestjs-libraries/agent/agent.graph.service';
import { Response } from 'express';
import { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.request';
import { CodeGenerationService } from '@gitroom/backend/services/code-generation/code-generation.service';
import { TestingService } from '@gitroom/backend/services/testing/testing.service';
import { CICDService } from '@gitroom/backend/services/cicd/cicd.service';

@ApiTags('Posts')
@Controller('/posts')
Expand All @@ -35,7 +38,10 @@ export class PostsController {
private _postsService: PostsService,
private _starsService: StarsService,
private _messagesService: MessagesService,
private _agentGraphService: AgentGraphService
private _agentGraphService: AgentGraphService,
private _codeGenerationService: CodeGenerationService,
private _testingService: TestingService,
private _cicdService: CICDService
) {}

@Get('/marketplace/:id?')
Expand Down Expand Up @@ -138,6 +144,34 @@ export class PostsController {
res.end();
}

@Post('/code-generation')
async generateCode(
@GetOrgFromRequest() org: Organization,
@Body() body: { userStoryId: string }
) {
return this._codeGenerationService.generateCode(org.id, body.userStoryId);
}

@Post('/testing/unit')
async runUnitTests(@GetOrgFromRequest() org: Organization) {
return this._testingService.runUnitTests(org.id);
}

@Post('/testing/integration')
async runIntegrationTests(@GetOrgFromRequest() org: Organization) {
return this._testingService.runIntegrationTests(org.id);
}

@Post('/testing/e2e')
async runE2ETests(@GetOrgFromRequest() org: Organization) {
return this._testingService.runE2ETests(org.id);
}

@Post('/cicd/pipeline')
async triggerCICDPipeline(@GetOrgFromRequest() org: Organization) {
return this._cicdService.triggerPipeline(org.id);
}
Comment on lines +147 to +173
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling to new methods

The methods generateCode, runUnitTests, runIntegrationTests, runE2ETests, and triggerCICDPipeline lack error handling. This may lead to unhandled promise rejections and unclear error responses to the client. Wrap these methods in try-catch blocks to handle exceptions gracefully.

Example:

@Post('/code-generation')
async generateCode(
  @GetOrgFromRequest() org: Organization,
  @Body() body: { userStoryId: string }
) {
  try {
    return await this._codeGenerationService.generateCode(org.id, body.userStoryId);
  } catch (e) {
    throw new BadRequestException(e.message);
  }
}

Ensure you import the necessary exceptions from @nestjs/common.


@Delete('/:group')
deletePost(
@GetOrgFromRequest() org: Organization,
Expand Down
35 changes: 35 additions & 0 deletions docker-compose.dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,41 @@ services:
networks:
- postiz-network
restart: always
postiz-backend:
build:
context: .
dockerfile: Dockerfile.dev
target: devcontainer
container_name: postiz-backend
restart: always
environment:
DATABASE_URL: "postgresql://postiz-local:postiz-local-pwd@postiz-postgres:5432/postiz-db-local"
REDIS_URL: "redis://postiz-redis:6379"
JWT_SECRET: "random string for your JWT secret, make it long"
FRONTEND_URL: "http://localhost:4200"
NEXT_PUBLIC_BACKEND_URL: "http://localhost:3000"
BACKEND_INTERNAL_URL: "http://localhost:3000"
volumes:
- ./apps/backend:/app
ports:
- 3000:3000
networks:
- postiz-network
Comment on lines +51 to +70
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enhance backend service configuration security and reliability

The backend service configuration needs improvements:

  1. Move sensitive environment variables to .env file
  2. Add health checks
  3. Configure resource limits
  4. Use secrets for sensitive data
   postiz-backend:
     build:
       context: .
       dockerfile: Dockerfile.dev
       target: devcontainer
     container_name: postiz-backend
     restart: always
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+    deploy:
+      resources:
+        limits:
+          cpus: '1'
+          memory: 1G
     environment:
       DATABASE_URL: "postgresql://postiz-local:postiz-local-pwd@postiz-postgres:5432/postiz-db-local"
       REDIS_URL: "redis://postiz-redis:6379"
-      JWT_SECRET: "random string for your JWT secret, make it long"
+      JWT_SECRET: ${JWT_SECRET}
       FRONTEND_URL: "http://localhost:4200"
       NEXT_PUBLIC_BACKEND_URL: "http://localhost:3000"
       BACKEND_INTERNAL_URL: "http://localhost:3000"
📝 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
postiz-backend:
build:
context: .
dockerfile: Dockerfile.dev
target: devcontainer
container_name: postiz-backend
restart: always
environment:
DATABASE_URL: "postgresql://postiz-local:postiz-local-pwd@postiz-postgres:5432/postiz-db-local"
REDIS_URL: "redis://postiz-redis:6379"
JWT_SECRET: "random string for your JWT secret, make it long"
FRONTEND_URL: "http://localhost:4200"
NEXT_PUBLIC_BACKEND_URL: "http://localhost:3000"
BACKEND_INTERNAL_URL: "http://localhost:3000"
volumes:
- ./apps/backend:/app
ports:
- 3000:3000
networks:
- postiz-network
postiz-backend:
build:
context: .
dockerfile: Dockerfile.dev
target: devcontainer
container_name: postiz-backend
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '1'
memory: 1G
environment:
DATABASE_URL: "postgresql://postiz-local:postiz-local-pwd@postiz-postgres:5432/postiz-db-local"
REDIS_URL: "redis://postiz-redis:6379"
JWT_SECRET: ${JWT_SECRET}
FRONTEND_URL: "http://localhost:4200"
NEXT_PUBLIC_BACKEND_URL: "http://localhost:3000"
BACKEND_INTERNAL_URL: "http://localhost:3000"
volumes:
- ./apps/backend:/app
ports:
- 3000:3000
networks:
- postiz-network

postiz-frontend:
build:
context: .
dockerfile: Dockerfile.dev
target: devcontainer
container_name: postiz-frontend
restart: always
environment:
NEXT_PUBLIC_BACKEND_URL: "http://localhost:3000"
volumes:
- ./apps/frontend:/app
ports:
- 4200:4200
networks:
- postiz-network
Comment on lines +71 to +85
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add health check and resource limits to frontend service

The frontend service configuration needs similar improvements:

  1. Add health check
  2. Configure resource limits
   postiz-frontend:
     build:
       context: .
       dockerfile: Dockerfile.dev
       target: devcontainer
     container_name: postiz-frontend
     restart: always
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:4200"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+    deploy:
+      resources:
+        limits:
+          cpus: '0.5'
+          memory: 512M
     environment:
       NEXT_PUBLIC_BACKEND_URL: "http://localhost:3000"
📝 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
postiz-frontend:
build:
context: .
dockerfile: Dockerfile.dev
target: devcontainer
container_name: postiz-frontend
restart: always
environment:
NEXT_PUBLIC_BACKEND_URL: "http://localhost:3000"
volumes:
- ./apps/frontend:/app
ports:
- 4200:4200
networks:
- postiz-network
postiz-frontend:
build:
context: .
dockerfile: Dockerfile.dev
target: devcontainer
container_name: postiz-frontend
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4200"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
environment:
NEXT_PUBLIC_BACKEND_URL: "http://localhost:3000"
volumes:
- ./apps/frontend:/app
ports:
- 4200:4200
networks:
- postiz-network


volumes:
redisinsight:
Expand Down
14 changes: 14 additions & 0 deletions setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

# Install necessary dependencies and tools
echo "Installing necessary dependencies and tools..."
npm install -g @nestjs/cli
npm install

# Set up environment variables and configuration files
echo "Setting up environment variables and configuration files..."
cp .env.example .env

# Launch the project using Docker Compose
echo "Launching the project using Docker Compose..."
docker-compose -f docker-compose.dev.yaml up --build
Comment on lines +1 to +14
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and prerequisite checks

The setup script needs improvements for reliability:

  1. Check for required tools (docker, npm)
  2. Validate environment file copy
  3. Add error handling
  4. Implement cleanup on failure
 #!/bin/bash
+set -euo pipefail
+
+# Function to check prerequisites
+check_prerequisites() {
+  command -v docker >/dev/null 2>&1 || { echo "Docker is required but not installed. Aborting." >&2; exit 1; }
+  command -v npm >/dev/null 2>&1 || { echo "npm is required but not installed. Aborting." >&2; exit 1; }
+}
+
+# Function to clean up on failure
+cleanup() {
+  echo "Setup failed. Cleaning up..."
+  docker-compose -f docker-compose.dev.yaml down
+  exit 1
+}
+
+# Set up error handling
+trap cleanup ERR
+
+# Check prerequisites
+check_prerequisites
 
 # Install necessary dependencies and tools
 echo "Installing necessary dependencies and tools..."
 npm install -g @nestjs/cli
-npm install
+npm install || { echo "Failed to install dependencies. Aborting." >&2; exit 1; }
 
 # Set up environment variables and configuration files
 echo "Setting up environment variables and configuration files..."
-cp .env.example .env
+if [ ! -f .env.example ]; then
+  echo ".env.example not found. Aborting." >&2
+  exit 1
+fi
+cp .env.example .env || { echo "Failed to create .env file. Aborting." >&2; exit 1; }
 
 # Launch the project using Docker Compose
 echo "Launching the project using Docker Compose..."
-docker-compose -f docker-compose.dev.yaml up --build
+docker-compose -f docker-compose.dev.yaml up --build || cleanup
📝 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
#!/bin/bash
# Install necessary dependencies and tools
echo "Installing necessary dependencies and tools..."
npm install -g @nestjs/cli
npm install
# Set up environment variables and configuration files
echo "Setting up environment variables and configuration files..."
cp .env.example .env
# Launch the project using Docker Compose
echo "Launching the project using Docker Compose..."
docker-compose -f docker-compose.dev.yaml up --build
#!/bin/bash
set -euo pipefail
# Function to check prerequisites
check_prerequisites() {
command -v docker >/dev/null 2>&1 || { echo "Docker is required but not installed. Aborting." >&2; exit 1; }
command -v npm >/dev/null 2>&1 || { echo "npm is required but not installed. Aborting." >&2; exit 1; }
}
# Function to clean up on failure
cleanup() {
echo "Setup failed. Cleaning up..."
docker-compose -f docker-compose.dev.yaml down
exit 1
}
# Set up error handling
trap cleanup ERR
# Check prerequisites
check_prerequisites
# Install necessary dependencies and tools
echo "Installing necessary dependencies and tools..."
npm install -g @nestjs/cli
npm install || { echo "Failed to install dependencies. Aborting." >&2; exit 1; }
# Set up environment variables and configuration files
echo "Setting up environment variables and configuration files..."
if [ ! -f .env.example ]; then
echo ".env.example not found. Aborting." >&2
exit 1
fi
cp .env.example .env || { echo "Failed to create .env file. Aborting." >&2; exit 1; }
# Launch the project using Docker Compose
echo "Launching the project using Docker Compose..."
docker-compose -f docker-compose.dev.yaml up --build || cleanup