diff --git a/.env.example b/.env.example index 691c37f..2525417 100644 --- a/.env.example +++ b/.env.example @@ -5,7 +5,7 @@ NODE_ENV=dev AWS_ENDPOINT=http://localstack:4566 AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test -AWS_DEFAULT_REGION=us-east-1 +AWS_REGION=us-east-1 GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= @@ -13,5 +13,3 @@ GOOGLE_CLIENT_SECRET= JWT_SECRET=foo DATABASE_URL=postgresql://username:password@postgres:5432/database?schema=public - -NOTIFICATIONS_EMAIL=foo@gmail.com diff --git a/.github/workflows/api-deploy.yml b/.github/workflows/api-deploy.yml new file mode 100644 index 0000000..d276994 --- /dev/null +++ b/.github/workflows/api-deploy.yml @@ -0,0 +1,52 @@ +name: CI/CD Pipeline + +on: + push: + branches: + - master + # - release + # paths: + # - 'src/**' + +jobs: + build-deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Create .env file + uses: SpicyPizza/create-envfile@v2.0 + with: + file_name: .env.production + fail_on_empty: false + sort_keys: false + envkey_PORT: ${{ secrets.PORT }} + envkey_NODE_ENV: ${{ secrets.NODE_ENV }} + envkey_AWS_REGION: ${{ secrets.AWS_REGION }} + envkey_GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }} + envkey_GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }} + envkey_JWT_SECRET: ${{ secrets.JWT_SECRET }} + envkey_DATABASE_URL: ${{ secrets.DATABASE_URL }} + + - name: Build + run: | + yarn install --ignore-scripts + yarn build + + - name: AWS CodeBuild & CodeDeploy + uses: sourcetoad/aws-codedeploy-action@v1 + with: + aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws_region: ${{ secrets.AWS_REGION }} + codedeploy_name: Econominhas + codedeploy_group: development_gropup + s3_bucket: econominhas-dev-api-deploy + s3_folder: api + max_polling_iterations: 60 + directory: dist diff --git a/.github/workflows/dbdocs-deploy.yml b/.github/workflows/dbdocs-deploy.yml index b76f070..77daf7e 100644 --- a/.github/workflows/dbdocs-deploy.yml +++ b/.github/workflows/dbdocs-deploy.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '20.x' diff --git a/.github/workflows/dbdocs-validate.yml b/.github/workflows/dbdocs-validate.yml index 1920797..f2b5882 100644 --- a/.github/workflows/dbdocs-validate.yml +++ b/.github/workflows/dbdocs-validate.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '20.x' diff --git a/.github/workflows/openapi-validate.yml b/.github/workflows/openapi-validate.yml index 79ede68..8cce325 100644 --- a/.github/workflows/openapi-validate.yml +++ b/.github/workflows/openapi-validate.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '20.x' diff --git a/.github/workflows/prisma-validate.yml b/.github/workflows/prisma-validate.yml index cb95752..4bf64a0 100644 --- a/.github/workflows/prisma-validate.yml +++ b/.github/workflows/prisma-validate.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '20.x' diff --git a/appspec.yml b/appspec.yml new file mode 100644 index 0000000..42d2531 --- /dev/null +++ b/appspec.yml @@ -0,0 +1,33 @@ +version: 0.0 +os: linux +files: + - source: / + destination: /home/ubuntu/econominhas +file_exists_behavior: OVERWRITE +permissions: + - object: /home/ubuntu/econominhas + pattern: "**" + owner: ec2-user + mode: 777 + type: + - directory +hooks: + ApplicationStop: + - location: scripts/cd-stop.sh + timeout: 300 + runas: ec2-user + + AfterInstall: + - location: scripts/cd-prepare.sh + timeout: 300 + runas: ec2-user + + ApplicationStart: + - location: scripts/cd-start.sh + timeout: 300 + runas: ec2-user + + ValidateService: + - location: scripts/cd-validate.sh + timeout: 300 + runas: ec2-user diff --git a/scripts/build.sh b/scripts/build.sh index 0916aac..7b87f00 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,10 +1,14 @@ #!/bin/bash +# Generate prisma client +npx prisma generate --generator client + # Build npx nest build --builder webpack # Create necessary folders mkdir dist/prisma +mkdir dist/scripts # Copy env files cp .env.production dist/.env @@ -16,3 +20,10 @@ cp yarn.lock dist/yarn.lock # Copy database files cp -r prisma/migrations dist/prisma/migrations cp prisma/schema.prisma dist/prisma/schema.prisma + +# Copy deploy files +cp appspec.yml dist/appspec.yml +cp scripts/cd-prepare.sh dist/scripts/cd-prepare.sh +cp scripts/cd-start.sh dist/scripts/cd-start.sh +cp scripts/cd-stop.sh dist/scripts/cd-stop.sh +cp scripts/cd-validate.sh dist/scripts/cd-validate.sh diff --git a/scripts/cd-prepare.sh b/scripts/cd-prepare.sh new file mode 100644 index 0000000..86e9433 --- /dev/null +++ b/scripts/cd-prepare.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion + +# Go to project folder +cd /home/ubuntu/econominhas + +# Install dependencies +yarn install --production=true --frozen-lockfile --ignore-scripts + +# Generate prisma client +npx prisma generate --generator client diff --git a/scripts/cd-start.sh b/scripts/cd-start.sh new file mode 100644 index 0000000..766edef --- /dev/null +++ b/scripts/cd-start.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion + +# Start new build +pm2 start "yarn start:prod" --name "ECONOMINHAS" diff --git a/scripts/cd-stop.sh b/scripts/cd-stop.sh new file mode 100644 index 0000000..254ff79 --- /dev/null +++ b/scripts/cd-stop.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion + +# Stop previous build (if running) +if pm2 list | grep -q 'ECONOMINHAS'; +then + pm2 delete "ECONOMINHAS" || : +fi diff --git a/scripts/cd-validate.sh b/scripts/cd-validate.sh new file mode 100644 index 0000000..b37e96c --- /dev/null +++ b/scripts/cd-validate.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion + +# Validate service +if pm2 status "ECONOMINHAS" | grep -q 'online'; +then + exit 0 +else + pm2 status "ECONOMINHAS" + exit 1 +fi diff --git a/src/adapters/implementations/s3/s3.service.ts b/src/adapters/implementations/s3/s3.service.ts index 1d7531a..8017e77 100644 --- a/src/adapters/implementations/s3/s3.service.ts +++ b/src/adapters/implementations/s3/s3.service.ts @@ -22,7 +22,7 @@ export class S3AdapterService extends FileAdapter { this.client = new S3Client({ endpoint: this.config.get('AWS_ENDPOINT'), - region: this.config.get('AWS_DEFAULT_REGION'), + region: this.config.get('AWS_REGION'), credentials: { secretAccessKey: this.config.get('AWS_SECRET_ACCESS_KEY'), accessKeyId: this.config.get('AWS_ACCESS_KEY_ID'), diff --git a/src/adapters/implementations/ses/ses.service.ts b/src/adapters/implementations/ses/ses.service.ts index f491672..23dfb51 100644 --- a/src/adapters/implementations/ses/ses.service.ts +++ b/src/adapters/implementations/ses/ses.service.ts @@ -19,7 +19,7 @@ export class SESAdapterService extends EmailAdapter { this.client = new SESClient({ endpoint: this.config.get('AWS_ENDPOINT'), - region: this.config.get('AWS_DEFAULT_REGION'), + region: this.config.get('AWS_REGION'), credentials: { secretAccessKey: this.config.get('AWS_SECRET_ACCESS_KEY'), accessKeyId: this.config.get('AWS_ACCESS_KEY_ID'), diff --git a/src/adapters/implementations/sns/sns.service.ts b/src/adapters/implementations/sns/sns.service.ts index e3621fe..4497f24 100644 --- a/src/adapters/implementations/sns/sns.service.ts +++ b/src/adapters/implementations/sns/sns.service.ts @@ -19,7 +19,7 @@ export class SNSAdapterService extends SmsAdapter { this.client = new SNSClient({ endpoint: this.config.get('AWS_ENDPOINT'), - region: this.config.get('AWS_DEFAULT_REGION'), + region: this.config.get('AWS_REGION'), credentials: { secretAccessKey: this.config.get('AWS_SECRET_ACCESS_KEY'), accessKeyId: this.config.get('AWS_ACCESS_KEY_ID'), diff --git a/src/config.ts b/src/config.ts index 42d8b3f..9f0d5b7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,7 +1,6 @@ import type { ConfigService } from '@nestjs/config'; import { Transform, plainToInstance } from 'class-transformer'; import { - IsEmail, IsIn, IsInt, IsOptional, @@ -28,7 +27,7 @@ class EnvVars { @IsString() AWS_SECRET_ACCESS_KEY: string; @IsIn(['us-east-1']) - AWS_DEFAULT_REGION: string; + AWS_REGION: string; @IsString() GOOGLE_CLIENT_ID: string; @@ -40,9 +39,6 @@ class EnvVars { @IsString() DATABASE_URL: string; - - @IsEmail() - NOTIFICATIONS_EMAIL: string; } export type AppConfig = ConfigService;