Skip to content

Commit

Permalink
Merge pull request #1 from theapexlab/project-setup
Browse files Browse the repository at this point in the history
Project setup
  • Loading branch information
BaDo2001 authored Oct 13, 2023
2 parents 2691170 + d690a4f commit 7cad267
Show file tree
Hide file tree
Showing 20 changed files with 1,157 additions and 34 deletions.
18 changes: 18 additions & 0 deletions .github/mergeable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: 2

mergeable:
- when: pull_request.*
name: "Description check"
validate:
- do: description
no_empty:
enabled: true
message: Description matter and should not be empty. Provide detail with **what** was changed, **why** it was changed, and **how** it was changed.

- when: pull_request.*, pull_request_review.*
name: "Title check"
validate:
- do: title
no_empty:
enabled: true
message: Title should not be empty.
35 changes: 35 additions & 0 deletions .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: PR checks

on: pull_request

jobs:
lint-build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_STAGING }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_STAGING }}
aws-region: eu-central-1

- uses: actions/setup-node@v3
with:
node-version: "18"

- name: Install Dependencies and Lint
run: |
yarn
yarn lint
- name: Build
run: yarn build --stage pr

- name: Test
run: yarn test:ci

- name: SIB
run: yarn sib --pipeline
41 changes: 41 additions & 0 deletions .github/workflows/staging.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Staging release

on:
push:
branches:
- main

jobs:
deploy:
env:
stage: staging

runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_STAGING }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_STAGING }}
aws-region: eu-central-1

- uses: actions/setup-node@v3
with:
node-version: "18"

- name: Install dependencies
run: yarn

- name: Set secrets
run: |
npx sst secrets set SLACK_LOG_LEVEL "${{ secrets.SLACK_LOG_LEVEL_STAGING }}" --stage "${{ env.stage }}"
npx sst secrets set SLACK_BOT_TOKEN "${{ secrets.SLACK_BOT_TOKEN_STAGING }}" --stage "${{ env.stage }}"
npx sst secrets set SLACK_SIGNING_SECRET "${{ secrets.SLACK_SIGNING_SECRET_STAGING }}" --stage "${{ env.stage }}"
npx sst secrets set CORE_SLACK_CHANNEL_ID "${{ secrets.CORE_SLACK_CHANNEL_ID_STAGING }}" --stage "${{ env.stage }}"
npx sst secrets set RANDOM_SLACK_CHANNEL_ID "${{ secrets.RANDOM_SLACK_CHANNEL_ID_STAGING }}" --stage "${{ env.stage }}"
- name: Deploy stack
run: yarn deploy --stage "${{ env.stage }}"
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"typecheck": "tsc --noEmit",
"lint": "eslint . --ext ts --report-unused-disable-directives --max-warnings 0",
"format": "prettier --write \"**/*.ts\"",
"prepare": "husky install"
"format:check": "prettier --check \"**/*.ts\"",
"prepare": "husky install",
"test:ci": "vitest run --passWithNoTests"
},
"dependencies": {
"sst": "^2.28.1"
Expand Down
21 changes: 21 additions & 0 deletions packages/functions/cron/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { sendQueueMessage } from "@/services/sqs/sendQueueMessage";

export const handler = async () => {
try {
const queueUrl = process.env.processTriggerJobQueueUrl;
if (!queueUrl) {
throw new Error("No queue url");
}

await sendQueueMessage(queueUrl, {});

return {
statusCode: 200,
};
} catch (error) {
console.error(`Error handling trigger jobs: ${error as string}`);
return {
statusCode: 500,
};
}
};
5 changes: 0 additions & 5 deletions packages/functions/lambdas/healthcheck.ts

This file was deleted.

4 changes: 4 additions & 0 deletions packages/functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@
"@types/node": "^20.8.4",
"sst": "^2.28.1",
"vitest": "^0.34.6"
},
"dependencies": {
"@aws-sdk/client-sqs": "^3.428.0",
"@slack/bolt": "^3.14.0"
}
}
15 changes: 15 additions & 0 deletions packages/functions/queues/process-cron-job-queue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { SQSHandler } from "aws-lambda";
import { Config } from "sst/node/config";

import { sendSlackMessage } from "@/services/slack/sendSlackMessage";

export const handler: SQSHandler = async () => {
try {
await sendSlackMessage(
Config.CORE_SLACK_CHANNEL_ID,
"Hello from Birthday bot!",
);
} catch (error) {
console.error(`Error processing trigger jobs: ${error as string}`);
}
};
21 changes: 21 additions & 0 deletions packages/functions/services/slack/createSlackApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { LogLevel } from "@slack/bolt";
import { App } from "@slack/bolt";
import { Config } from "sst/node/config";

export const createSlackApp = () => {
const token = Config.SLACK_BOT_TOKEN;
const signingSecret = Config.SLACK_SIGNING_SECRET;
const logLevel = Config.SLACK_LOG_LEVEL as LogLevel;

if (!token || !signingSecret || !logLevel) {
throw new Error("Missing Slack config");
}

const app = new App({
signingSecret,
token,
logLevel,
});

return app;
};
15 changes: 15 additions & 0 deletions packages/functions/services/slack/getChannelUsers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createSlackApp } from "./createSlackApp";

export const getSlackChannelUsers = async (channelId: string) => {
const app = createSlackApp();

const { members } = await app.client.conversations.members({
channel: channelId,
});

if (!members) {
throw new Error("Error while fetching channel members");
}

return members;
};
10 changes: 10 additions & 0 deletions packages/functions/services/slack/sendSlackMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { createSlackApp } from "./createSlackApp";

export const sendSlackMessage = async (target: string, text: string) => {
const app = createSlackApp();

await app.client.chat.postMessage({
channel: target,
text,
});
};
12 changes: 12 additions & 0 deletions packages/functions/services/sqs/sendQueueMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { SendMessageCommand } from "@aws-sdk/client-sqs";

import { sqsClient } from "./sqsClient";

export const sendQueueMessage = async (queueUrl: string, body: object) => {
const message = new SendMessageCommand({
QueueUrl: queueUrl,
MessageBody: JSON.stringify(body),
});

await sqsClient.send(message);
};
3 changes: 3 additions & 0 deletions packages/functions/services/sqs/sqsClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SQSClient } from "@aws-sdk/client-sqs";

export const sqsClient = new SQSClient();
2 changes: 1 addition & 1 deletion packages/functions/sst-env.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import "../.sst/types/index";
import "../../.sst/types/index";
5 changes: 4 additions & 1 deletion packages/functions/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"compilerOptions": {
"module": "esnext",
"moduleResolution": "node",
"baseUrl": "."
"baseUrl": ".",
"paths": {
"@/services/*": ["services/*"]
}
}
}
4 changes: 3 additions & 1 deletion sst.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { SSTConfig } from "sst";

import { ConfigStack } from "./stacks/ConfigStack";
import { CronStack } from "./stacks/CronStack";
import { MyStack } from "./stacks/MyStack";

export default {
Expand All @@ -10,6 +12,6 @@ export default {
};
},
stacks(app) {
app.stack(MyStack);
app.stack(ConfigStack).stack(MyStack).stack(CronStack);
},
} satisfies SSTConfig;
23 changes: 23 additions & 0 deletions stacks/ConfigStack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Config, type StackContext } from "sst/constructs";

export function ConfigStack({ stack }: StackContext) {
const SLACK_LOG_LEVEL = new Config.Secret(stack, "SLACK_LOG_LEVEL");
const SLACK_BOT_TOKEN = new Config.Secret(stack, "SLACK_BOT_TOKEN");
const SLACK_SIGNING_SECRET = new Config.Secret(stack, "SLACK_SIGNING_SECRET");
const CORE_SLACK_CHANNEL_ID = new Config.Secret(
stack,
"CORE_SLACK_CHANNEL_ID",
);
const RANDOM_SLACK_CHANNEL_ID = new Config.Secret(
stack,
"RANDOM_SLACK_CHANNEL_ID",
);

return [
SLACK_LOG_LEVEL,
SLACK_BOT_TOKEN,
SLACK_SIGNING_SECRET,
CORE_SLACK_CHANNEL_ID,
RANDOM_SLACK_CHANNEL_ID,
];
}
27 changes: 27 additions & 0 deletions stacks/CronStack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { StackContext } from "sst/constructs";
import { Cron, use } from "sst/constructs";

import { MyStack } from "./MyStack";

export function CronStack({ stack }: StackContext) {
const { stage } = stack;
const isDev = stage !== "production";
const { processTriggerJob } = use(MyStack);

const triggerBirthdayJob = {
function: {
handler: "packages/functions/cron/index.handler",
bind: [processTriggerJob],
environment: {
processTriggerJobQueueUrl: processTriggerJob.queueUrl,
isDev: isDev.toString(),
},
},
};

new Cron(stack, "Birthday-dev-trigger", {
schedule: `rate(1 day)`,
job: triggerBirthdayJob,
enabled: isDev,
});
}
27 changes: 16 additions & 11 deletions stacks/MyStack.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import type { StackContext } from "sst/constructs";
import { Api } from "sst/constructs";
import { Queue, use } from "sst/constructs";

export function MyStack({ stack }: StackContext): void {
const api = new Api(stack, "api", {
defaults: {
function: {},
},
routes: {
"GET /healthcheck": "packages/functions/lambdas/healthcheck.handler",
import { ConfigStack } from "./ConfigStack";

export function MyStack({ stack }: StackContext) {
const secrets = use(ConfigStack);

const processTriggerJob = new Queue(stack, "process-trigger-job", {
consumer: {
function: {
handler: "packages/functions/queues/process-cron-job-queue.handler",
timeout: 10,
bind: secrets,
},
},
});

stack.addOutputs({
ApiEndpoint: api.url,
});
return {
processTriggerJob,
};
}
Loading

0 comments on commit 7cad267

Please sign in to comment.