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

Config/setup cicd #16

Merged
merged 5 commits into from
Sep 8, 2024
Merged
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
108 changes: 61 additions & 47 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,67 +10,79 @@ parameters:
enum: ['dev', 'prod']
default: 'dev'

executors:
node:
docker:
- image: cimg/node:16.16.0
orbs:
aws-cli: circleci/[email protected]

jobs:
build:
machine: true
machine:
image: ubuntu-2004:current
working_directory: ~/map-sorter-api
environment:
DOCKER_IMAGE: high10hunter/map-sorter-api
DOCKER_TAG: latest
steps:
- checkout
- restore_cache:
name: Restore NPM cache
keys:
- npm-cache-{{ checksum "package-lock.json" }}
- npm-cache-
- run:
name: Update NPM version
command: npm install -g npm@latest

- save_cache:
name: Save NPM cache
key: npm-cache-{{ checksum "package-lock.json" }}
paths:
- ~/.cache/npm
- ./node_modules
- run:
name: Install dependencies
command: npm ci
- run:
name: Run tests
command: npm run test
name: Login to DockerHub
command: echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin

- run:
name: Build
command: npm run build
name: Build and push image
command: |
echo "Building image"
docker build -t $DOCKER_IMAGE:$DOCKER_TAG .

echo "Pushing image"
docker push $DOCKER_IMAGE:$DOCKER_TAG

echo "::set-output name=image::$DOCKER_IMAGE:$DOCKER_TAG"

deploy:
executor: node
machine:
image: ubuntu-2004:current
working_directory: ~/map-sorter-api
steps:
- aws-cli/setup:
role-arn: 'arn:aws:iam::"$AWS_ACCOUNT_ID":role/circleci-oidc-provider-aws'
aws-region: $AWS_REGION
- checkout
- restore_cache:
name: Restore NPM cache
keys:
- npm-cache-{{ checksum "package-lock.json" }}
- npm-cache-

- add_ssh_keys:
fingerprints:
- 'SHA256:+2S1UpsWHcjQu4ur9jpqF16GQa9NrND9qbFNU6pzB64'

- run:
name: Create .env file
command: |
cd tools
aws ssm get-parameters-by-path --path "/dev" --with-decryption --recursive > mapsorter_env.json
./convert_ssm_params_to_dotenv.sh mapsorter_env.json

- run:
name: Sync .env file to dev server
command: |
scp -oStrictHostKeyChecking=no -r .env $SSH_USER@$SSH_HOST:~/map-sorter-api

- run:
name: Install dependencies
command: npm ci
- save_cache:
name: Save NPM cache
key: npm-cache-{{ checksum "package-lock.json" }}
paths:
- ~/.cache/npm
- ./node_modules
name: SSH into dev server
command: |
echo "SSH into dev server"
ssh -oStrictHostKeyChecking=no -v $SSH_USER@$SSH_HOST

- run:
name: Login to DockerHub
command: echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin

- run:
name: 'Deploy to << pipeline.parameters.build_stage >>'
name: 'Deploy to << pipeline.parameters.build_stage >> environment'
command: |
curl -i -H "X-Secret-Signature: $WEBHOOK_SECRET" \
-H "Content-Type: application/json" \
-X POST $WEBHOOK_URL/redeploy
echo "Deploying to << pipeline.parameters.build_stage >>"
docker pull $DOCKER_IMAGE:$DOCKER_TAG
docker container stop map-sorter-api || true
docker container rm map-sorter-api || true
docker run --log-opt max-size=10m --log-opt max-file=3 --log-opt compress=true --name map-sorter-api -d --env-file .env $DOCKER_IMAGE:$DOCKER_TAG
docker image prune --all -f

workflows:
version: 3
Expand All @@ -82,7 +94,7 @@ workflows:
- build:
filters:
branches:
only: develop
only: test

DeployDev:
# if the 'task' parameter equals 'deploy'
Expand All @@ -94,11 +106,12 @@ workflows:
jobs:
- build
- deploy:
context: aws
requires:
- build
filters:
branches:
only: develop
only: test

DeployProd:
# if the 'task' parameter equals 'deploy'
Expand All @@ -110,6 +123,7 @@ workflows:
jobs:
- build
- deploy:
context: aws
requires:
- build
filters:
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/build-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ name: Build
on:
pull_request:
types: [opened, synchronize]
branches: [develop]
# branches: [develop]
branches: [test]
jobs:
build:
runs-on: ubuntu-latest
Expand All @@ -14,5 +15,5 @@ jobs:
-X POST \
-H "Content-Type: application/json" \
-H "Circle-Token: ${{ secrets.CIRCLECI_TOKEN }}" \
--data '{"branch": "develop", "parameters": {"task": "build"}}' \
--data '{"branch": "test", "parameters": {"task": "build"}}' \
https://circleci.com/api/v2/project/gh/dscdut/map-sorter-api/pipeline
7 changes: 4 additions & 3 deletions .github/workflows/deploy-dev-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ name: DeployDev
on:
pull_request:
types: [closed]
branches: [develop]
# branches: [develop]
branches: [test]

jobs:
deploy:
if: ${{ github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'develop' }}
if: ${{ github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'test' }}
runs-on: ubuntu-latest

steps:
Expand All @@ -17,5 +18,5 @@ jobs:
-X POST \
-H "Content-Type: application/json" \
-H "Circle-Token: ${{ secrets.CIRCLECI_TOKEN }}" \
--data '{"branch": "develop", "parameters": {"task": "deploy", "build_stage": "dev"}}' \
--data '{"branch": "test", "parameters": {"task": "deploy", "build_stage": "dev"}}' \
https://circleci.com/api/v2/project/gh/dscdut/map-sorter-api/pipeline
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ lerna-debug.log*

# Environment files
.env
xata-credentials.txt

# Winston audit file
*-audit.json

ca-certificate.crt
/db/
/uploads/
/uploads/

44 changes: 19 additions & 25 deletions src/database/typeorm/config.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import fs from 'fs';
import { DataSource } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { config } from 'dotenv';
import entities from './entities';

config();
const configService = new ConfigService();

export const PostgresDataSource = new DataSource({
type: 'postgres',
host: configService.get('TYPEORM_HOST'),
port: configService.get<number>('TYPEORM_PORT'),
username: configService.get('TYPEORM_USERNAME'),
password: configService.get('TYPEORM_PASSWORD'),
database: configService.get('TYPEORM_DATABASE'),
entities,
ssl:
configService.get('DB_USE_SSL') === 'true'
? {
ca: fs.readFileSync('ca-certificate.crt'),
}
: undefined,
migrations: ['src/database/typeorm/migrations/*.ts'],
});
import { DataSource } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { config } from 'dotenv';
import entities from './entities';

config();
const configService = new ConfigService();

export const PostgresDataSource = new DataSource({
type: 'postgres',
host: configService.get('TYPEORM_HOST'),
port: configService.get<number>('TYPEORM_PORT'),
username: configService.get('TYPEORM_USERNAME'),
password: configService.get('TYPEORM_PASSWORD'),
database: configService.get('TYPEORM_DATABASE'),
entities,
ssl: configService.get('DB_USE_SSL') === 'true' ? true : undefined,
migrations: ['src/database/typeorm/migrations/*.ts'],
});
108 changes: 51 additions & 57 deletions src/shared/services/api-config.service.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,51 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import type { TypeOrmModuleOptions } from '@nestjs/typeorm';
import fs from 'fs';
import entities from '../../database/typeorm/entities';
import { config } from 'dotenv';

config();
@Injectable()
export class ApiConfigService {
constructor(private configService: ConfigService) {}

get isDevelopment(): boolean {
return this.nodeEnv === 'development';
}

get isProduction(): boolean {
return this.nodeEnv === 'production';
}

get isTest(): boolean {
return this.nodeEnv === 'test';
}

get nodeEnv(): string {
return this.configService.get('NODE_ENV');
}

get postgresConfig(): TypeOrmModuleOptions {
return {
type: 'postgres',
host: this.configService.get('TYPEORM_HOST'),
port: this.configService.get<number>('TYPEORM_PORT'),
username: this.configService.get('TYPEORM_USERNAME'),
password: this.configService.get('TYPEORM_PASSWORD'),
database: this.configService.get('TYPEORM_DATABASE'),
entities,
autoLoadEntities: true,
synchronize: false,
maxQueryExecutionTime:
this.configService.get<number>('DB_MAX_QUERY_TIME'),
ssl:
this.configService.get('DB_USE_SSL') === 'true'
? {
ca: fs.readFileSync('ca-certificate.crt'),
}
: undefined,
};
}

get authConfig() {
return {
secret: this.configService.get('JWT_SECRET'),
expiresIn: this.configService.get('JWT_EXPIRES_IN'),
};
}
}
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import type { TypeOrmModuleOptions } from '@nestjs/typeorm';
import entities from '../../database/typeorm/entities';
import { config } from 'dotenv';

config();
@Injectable()
export class ApiConfigService {
constructor(private configService: ConfigService) {}

get isDevelopment(): boolean {
return this.nodeEnv === 'development';
}

get isProduction(): boolean {
return this.nodeEnv === 'production';
}

get isTest(): boolean {
return this.nodeEnv === 'test';
}

get nodeEnv(): string {
return this.configService.get('NODE_ENV');
}

get postgresConfig(): TypeOrmModuleOptions {
return {
type: 'postgres',
host: this.configService.get('TYPEORM_HOST'),
port: this.configService.get<number>('TYPEORM_PORT'),
username: this.configService.get('TYPEORM_USERNAME'),
password: this.configService.get('TYPEORM_PASSWORD'),
database: this.configService.get('TYPEORM_DATABASE'),
entities,
autoLoadEntities: true,
synchronize: false,
maxQueryExecutionTime:
this.configService.get<number>('DB_MAX_QUERY_TIME'),
ssl: this.configService.get('DB_USE_SSL') === 'true' ? true : undefined,
};
}

get authConfig() {
return {
secret: this.configService.get('JWT_SECRET'),
expiresIn: this.configService.get('JWT_EXPIRES_IN'),
};
}
}
3 changes: 3 additions & 0 deletions tools/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
STRING_PARAM_1=value1
SECURE_STRING_PARAM_2=value2
STRING_LIST_PARAM_3=value3a,value3b,value3c
Loading