Skip to content

Commit

Permalink
Merge pull request #32 from wri/release/utltimate-ulmus
Browse files Browse the repository at this point in the history
[RELEASE] Utltimate Ulmus
  • Loading branch information
roguenet authored Dec 20, 2024
2 parents f96fb49 + 0c89622 commit ff0c3ed
Show file tree
Hide file tree
Showing 105 changed files with 6,188 additions and 1,942 deletions.
8 changes: 8 additions & 0 deletions .env.local.sample
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
USER_SERVICE_PORT=4010
JOB_SERVICE_PORT=4020
RESEARCH_SERVICE_PORT=4030
UNIFIED_DATABASE_SERVICE_PORT=4040
ENTITY_SERVICE_PORT=4050

DB_HOST=localhost
DB_PORT=3360
DB_DATABASE=wri_restoration_marketplace_api
DB_USERNAME=wri
DB_PASSWORD=wri

REDIS_HOST=localhost
REDIS_PORT=6379

JWT_SECRET=qu3sep4GKdbg6PiVPCKLKljHukXALorq6nLHDBOCSwvs6BrgE6zb8gPmZfrNspKt

# Only needed for the unified database service. Most developers should not have this defined.
AIRTABLE_API_KEY
1 change: 1 addition & 0 deletions .github/workflows/deploy-api-gateway.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ env:
AWS_ROLE_TO_ASSUME: arn:aws:iam::603634817705:role/terramatch-microservices-github-actions
AWS_ROLE_SESSION_NAME: terramatch-microservices-cicd-api-gateway
PHP_PROXY_TARGET: ${{ vars.PHP_PROXY_TARGET }}
ENABLED_SERVICES: ${{ vars.ENABLED_SERVICES }}

jobs:
deploy-api-gateway:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/deploy-service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ on:
required: true
options:
- job-service
- research-service
- user-service
- entity-service
- research-service
- unified-database-service
env:
description: 'Deployment target environment'
type: choice
Expand Down Expand Up @@ -69,7 +71,7 @@ jobs:
: # Don't build the base image with NODE_ENV because it'll limit the packages that are installed
docker build -t terramatch-microservices-base:nx-base .
SERVICE_IMAGE=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker build --build-arg NODE_ENV=production --build-arg BUILD_FLAG=--prod -f apps/${{ inputs.service }}/Dockerfile -t $SERVICE_IMAGE .
docker build --build-arg NODE_ENV=production --build-arg BUILD_FLAG='--prod --verbose' -f apps/${{ inputs.service }}/Dockerfile -t $SERVICE_IMAGE .
docker push $SERVICE_IMAGE
echo "image=$SERVICE_IMAGE"
Expand Down
42 changes: 41 additions & 1 deletion .github/workflows/deploy-services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,65 @@ permissions:
contents: read

jobs:
check-services:
runs-on: ubuntu-latest
environment: ${{ inputs.env }}
outputs:
job-service-enabled: ${{ steps.check-services.outputs.job }}
user-service-enabled: ${{ steps.check-services.outputs.user }}
entity-service-enabled: ${{ steps.check-services.outputs.entity }}
research-service-enabled: ${{ steps.check-services.outputs.research }}
unified-database-service-enabled: ${{ steps.check-services.outputs.unified-database }}
steps:
- id: check-services
run: |
echo "job=${{ vars.ENABLED_SERVICES == '' || contains(vars.ENABLED_SERVICES, 'job-service') }}" >> "$GITHUB_OUTPUT"
echo "user=${{ vars.ENABLED_SERVICES == '' || contains(vars.ENABLED_SERVICES, 'user-service') }}" >> "$GITHUB_OUTPUT"
echo "entity=${{ vars.ENABLED_SERVICES == '' || contains(vars.ENABLED_SERVICES, 'entity-service') }}" >> "$GITHUB_OUTPUT"
echo "research=${{ vars.ENABLED_SERVICES == '' || contains(vars.ENABLED_SERVICES, 'research-service') }}" >> "$GITHUB_OUTPUT"
echo "unified-database=${{ vars.ENABLED_SERVICES == '' || contains(vars.ENABLED_SERVICES, 'unified-database-service') }}" >> "$GITHUB_OUTPUT"
job-service:
needs: check-services
if: needs.check-services.outputs.job-service-enabled == 'true'
uses: ./.github/workflows/deploy-service.yml
with:
env: ${{ inputs.env }}
service: job-service
secrets: inherit

user-service:
needs: check-services
if: needs.check-services.outputs.user-service-enabled == 'true'
uses: ./.github/workflows/deploy-service.yml
with:
env: ${{ inputs.env }}
service: user-service
secrets: inherit

entity-service:
needs: check-services
if: needs.check-services.outputs.entity-service-enabled == 'true'
uses: ./.github/workflows/deploy-service.yml
with:
env: ${{ inputs.env }}
service: entity-service
secrets: inherit

research-service:
needs: check-services
if: needs.check-services.outputs.research-service-enabled == 'true'
uses: ./.github/workflows/deploy-service.yml
with:
env: ${{ inputs.env }}
service: research-service
secrets: inherit


unified-database-service:
needs: check-services
if: needs.check-services.outputs.unified-database-service-enabled == 'true'
uses: ./.github/workflows/deploy-service.yml
with:
env: ${{ inputs.env }}
service: unified-database-service
secrets: inherit
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,21 @@ and main branches.
* Set up the new `main.ts` similarly to existing services.
* Make sure swagger docs and the `/health` endpoint are implemented
* Pick a default local port that is unique from other services
* Make sure the top of `main.ts` has these two lines:
```
// eslint-disable-next-line @nx/enforce-module-boundaries
import "../../../instrument-sentry";
```
* Add the `SentryModule` and `SentryGlobalFilter` to your main `app.module.ts`. See an existing service for an example.
* In your `.env` and `.env.local.sample`, add `_PORT` for the new service
* In `api-gateway-stack.ts`, add the new service and namespace to `V3_SERVICES`
* In your local web repo, follow directions in `README.md` for setting up a new service.
* This step can be skipped for services that will not be used by the FE website.
* For deployment to AWS:
* Add a Dockerfile in the new app directory. A simple copy and modify from user-service is sufficient
* Add the new service name to the "service" workflow input options in `deploy-service.yml`
* Add a new job to `deploy-services.yml` to include the new services in the "all" service deployment workflow.
* Make sure to update the `check-services` step and follow the pattern for the `if` conditions on the individual service deploy jobs.
* In AWS:
* Add ECR repositories for each env (follow the naming scheme from user-service, e.g. `terramatch-microservices/foo-service-staging`, etc)
* Set the repo to Immutable
Expand Down
18 changes: 18 additions & 0 deletions apps/entity-service-e2e/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
19 changes: 19 additions & 0 deletions apps/entity-service-e2e/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* eslint-disable */
export default {
displayName: "entity-service-e2e",
preset: "../../jest.preset.js",
globalSetup: "<rootDir>/src/support/global-setup.ts",
globalTeardown: "<rootDir>/src/support/global-teardown.ts",
setupFiles: ["<rootDir>/src/support/test-setup.ts"],
testEnvironment: "node",
transform: {
"^.+\\.[tj]s$": [
"ts-jest",
{
tsconfig: "<rootDir>/tsconfig.spec.json"
}
]
},
moduleFileExtensions: ["ts", "js", "html"],
coverageDirectory: "../../coverage/entity-service-e2e"
};
17 changes: 17 additions & 0 deletions apps/entity-service-e2e/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "entity-service-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"implicitDependencies": ["entity-service"],
"targets": {
"e2e": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{e2eProjectRoot}"],
"options": {
"jestConfig": "apps/entity-service-e2e/jest.config.ts",
"passWithNoTests": true
},
"dependsOn": ["entity-service:build"]
}
}
}
10 changes: 10 additions & 0 deletions apps/entity-service-e2e/src/entity-service/entity-service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import axios from "axios";

describe("GET /api", () => {
it("should return a message", async () => {
const res = await axios.get(`/api`);

expect(res.status).toBe(200);
expect(res.data).toEqual({ message: "Hello API" });
});
});
10 changes: 10 additions & 0 deletions apps/entity-service-e2e/src/support/global-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* eslint-disable */
var __TEARDOWN_MESSAGE__: string;

module.exports = async function () {
// Start services that that the app needs to run (e.g. database, docker-compose, etc.).
console.log("\nSetting up...\n");

// Hint: Use `globalThis` to pass variables to global teardown.
globalThis.__TEARDOWN_MESSAGE__ = "\nTearing down...\n";
};
7 changes: 7 additions & 0 deletions apps/entity-service-e2e/src/support/global-teardown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* eslint-disable */

module.exports = async function () {
// Put clean up logic here (e.g. stopping services, docker-compose, etc.).
// Hint: `globalThis` is shared between setup and teardown.
console.log(globalThis.__TEARDOWN_MESSAGE__);
};
10 changes: 10 additions & 0 deletions apps/entity-service-e2e/src/support/test-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* eslint-disable */

import axios from "axios";

module.exports = async function () {
// Configure axios for tests to use.
const host = process.env.HOST ?? "localhost";
const port = process.env.PORT ?? "3000";
axios.defaults.baseURL = `http://${host}:${port}`;
};
13 changes: 13 additions & 0 deletions apps/entity-service-e2e/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.spec.json"
}
],
"compilerOptions": {
"esModuleInterop": true
}
}
9 changes: 9 additions & 0 deletions apps/entity-service-e2e/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": ["jest.config.ts", "src/**/*.ts"]
}
18 changes: 18 additions & 0 deletions apps/entity-service/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
15 changes: 15 additions & 0 deletions apps/entity-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM terramatch-microservices-base:nx-base AS builder

ARG BUILD_FLAG
WORKDIR /app/builder
COPY . .
RUN npx nx build entity-service ${BUILD_FLAG}

FROM terramatch-microservices-base:nx-base

ARG NODE_ENV
WORKDIR /app
COPY --from=builder /app/builder ./
ENV NODE_ENV=${NODE_ENV}

CMD ["node", "./dist/apps/entity-service/main.js"]
11 changes: 11 additions & 0 deletions apps/entity-service/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* eslint-disable */
export default {
displayName: "entity-service",
preset: "../../jest.preset.js",
testEnvironment: "node",
transform: {
"^.+\\.[tj]s$": ["ts-jest", { tsconfig: "<rootDir>/tsconfig.spec.json" }]
},
moduleFileExtensions: ["ts", "js", "html"],
coverageDirectory: "../../coverage/apps/entity-service"
};
26 changes: 26 additions & 0 deletions apps/entity-service/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "entity-service",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/entity-service/src",
"projectType": "application",
"tags": [],
"targets": {
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"dependsOn": ["build"],
"options": {
"buildTarget": "entity-service:build",
"runBuildTargetDependencies": false
},
"configurations": {
"development": {
"buildTarget": "entity-service:build:development"
},
"production": {
"buildTarget": "entity-service:build:production"
}
}
}
}
}
21 changes: 21 additions & 0 deletions apps/entity-service/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Module } from "@nestjs/common";
import { DatabaseModule } from "@terramatch-microservices/database";
import { CommonModule } from "@terramatch-microservices/common";
import { HealthModule } from "./health/health.module";
import { TreesController } from "./trees/trees.controller";
import { TreeService } from "./trees/tree.service";
import { SentryGlobalFilter, SentryModule } from "@sentry/nestjs/setup";
import { APP_FILTER } from "@nestjs/core";

@Module({
imports: [SentryModule.forRoot(), DatabaseModule, CommonModule, HealthModule],
controllers: [TreesController],
providers: [
{
provide: APP_FILTER,
useClass: SentryGlobalFilter
},
TreeService
]
})
export class AppModule {}
Empty file.
28 changes: 28 additions & 0 deletions apps/entity-service/src/health/health.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Controller, Get } from '@nestjs/common';
import { HealthCheck, HealthCheckService, SequelizeHealthIndicator } from '@nestjs/terminus';
import { NoBearerAuth } from '@terramatch-microservices/common/guards';
import { ApiExcludeController } from '@nestjs/swagger';
import { User } from '@terramatch-microservices/database/entities';

@Controller('health')
@ApiExcludeController()
export class HealthController {
constructor(
private readonly health: HealthCheckService,
private readonly db: SequelizeHealthIndicator
) {}

@Get()
@HealthCheck()
@NoBearerAuth
async check() {
const connection = await User.sequelize.connectionManager.getConnection({ type: 'read' });
try {
return this.health.check([
() => this.db.pingCheck('database', { connection })
]);
} finally {
User.sequelize.connectionManager.releaseConnection(connection);
}
}
}
9 changes: 9 additions & 0 deletions apps/entity-service/src/health/health.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from './health.controller';

@Module({
imports: [TerminusModule],
controllers: [HealthController],
})
export class HealthModule {}
Loading

0 comments on commit ff0c3ed

Please sign in to comment.