Skip to content

Commit

Permalink
feat: improvements to v3
Browse files Browse the repository at this point in the history
  • Loading branch information
FilipPyrek committed Feb 2, 2024
1 parent 8a1ae84 commit ea2e909
Show file tree
Hide file tree
Showing 25 changed files with 375 additions and 73 deletions.
3 changes: 3 additions & 0 deletions .env-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
AWS_SDK_LOAD_CONFIG=true
AWS_PROFILE=your-aws-profile
AWS_REGION=eu-central-1
41 changes: 41 additions & 0 deletions .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Deploy
on:
workflow_dispatch:
push:
branches:
- master
- staging
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2

- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
cache-dependency-path: pnpm-lock.yaml

- name: Install Dependencies
run: pnpm install

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
role-to-assume: ${{ github.ref == 'refs/heads/master' && 'CHANGE_ME' || 'CHANGE_ME' }}
aws-region: eu-central-1 # Is not relate to deployment region
role-session-name: CHANGE_ME

- name: Deploy
run: pnpm sst deploy
53 changes: 53 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Create Release

on:
workflow_run:
workflows: [Deploy]
branches: [master]
types: [completed]

jobs:
create_release_notes:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout Repository
uses: actions/checkout@v2

- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
cache-dependency-path: pnpm-lock.yaml

- name: Install dependencies
run: pnpm install

- name: Release
run: |
pnpm semantic-release --dry-run | \
awk '/The next release version is ([0-9]+\.[0-9]+\.[0-9]+)/{ print $0 }' | \
awk '{split($0, array, "version is "); print array[2]}' > version.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Create Release
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/${{github.repository}}/releases \
-f tag_name="v$(cat version.txt)" \
-f target_commitish=${{github.ref}} \
-f name="Production v$(cat version.txt)" \
-F generate_release_notes=true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37 changes: 37 additions & 0 deletions .github/workflows/remove.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Remove Deployment
on:
workflow_dispatch:
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2

- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
cache-dependency-path: pnpm-lock.yaml

- name: Install Dependencies
run: pnpm install

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
role-to-assume: ${{ github.ref == 'refs/heads/master' && 'CHANGE_ME' || 'CHANGE_ME' }}
aws-region: eu-central-1 # Is not relate to deployment region
role-session-name: CHANGE_ME

- name: Deploy
run: pnpm sst remove
51 changes: 51 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Test
on:
workflow_dispatch:
push:
branches:
- f/*

permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v2

- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
cache-dependency-path: pnpm-lock.yaml

- name: Install Dependencies
run: pnpm install

- name: Commit Lint
run: pnpm commitlint --from CHANGE_ME --to HEAD

- name: Code Lint
run: pnpm run lint

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
role-to-assume: ${{ github.ref == 'refs/heads/master' && 'CHANGE_ME' || 'CHANGE_ME' }}
aws-region: eu-central-1 # Is not relate to deployment region
role-session-name: CHANGE_ME

- name: Type check
run: pnpm run ci:typecheck:all

- name: Test
run: pnpm run test
7 changes: 7 additions & 0 deletions .releaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"release": {
"branches": [
"master"
]
}
}
136 changes: 135 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,135 @@
hello
# Purple Stack

<p align="center">
<img width="727" alt="9 Landscape Gradient@2x" src="https://user-images.githubusercontent.com/6282843/165325934-63b58d78-a395-4e0a-a27e-ab41aafecb41.png">
</p>

![GitHub top language](https://img.shields.io/github/languages/top/purple-technology/purple-stack)
![GitHub last commit](https://img.shields.io/github/last-commit/purple-technology/purple-stack)
![GitHub](https://img.shields.io/github/license/purple-technology/purple-stack)


Make sure to replace all `CHANGE_ME` values in the repo.

## What is Purple Stack

Purple stack is a development stack designed by [Purple LAB](https://www.purple-technology.com/) for developing full-stack serverless apps.

It's based on our 6+ years of experience with building big Serverless apps on AWS.

You can read more about how Purple Stack was born on our [blog](https://blog.purple-technology.com/cs/pribeh-o-tom-ako-vznikol-purplestack/).

## Tech being used

- Main language: [TypeScript](https://www.typescriptlang.org/)
- Deployment framework: [SST.dev](https://sst.dev/)
- Frontend: [React.js](https://react.dev) & [Next.js](https://nextjs.org/)
- Code bundling: [ESbuild](https://esbuild.github.io/)
- Package manager: [PNPM](https://pnpm.io/)
- Linting: [ESlint](https://eslint.org/) & [Prettier](https://prettier.io/)
- API protocol: [tRPC](https://trpc.io/)
- Business workflows engine: [AWS Step Functions](https://aws.amazon.com/step-functions/)
- CI/CD: [GitHub Actions](https://github.com/features/actions)
- Static Application Security Testing (SAST) - [`eslint-plugin-security`](https://www.npmjs.com/package/eslint-plugin-security) & [@microsoft/eslint-plugin-sdl](https://www.npmjs.com/package/@microsoft/eslint-plugin-sdl)
- Unit Tests - [Vitest](https://vitest.dev/)
- Structured Logging: [AWS Lambda Powertools Logger](https://docs.powertools.aws.dev/lambda/typescript/latest/core/logger/)
- Conventional Commits - [Commitlint](https://commitlint.js.org)
- ... and more

## File structure

```
.
β”œβ”€β”€ constructs
β”‚ └── # Here go sharable CDK constructs that
β”‚ # you can abstract for multiple services.
β”‚ #
β”‚ # Only individual TS files. No packages.
β”œβ”€β”€ packages
β”‚ └── # Here goes any application code that
β”‚ # you need to share between services.
β”‚ #
β”‚ # Make sure the packages are created
β”‚ # as "npm" packages so that they have
β”‚ # package.json and tsconfig.ts files.
β”œβ”€β”€ services
β”‚ └── # Here goes source code for indivudual
β”‚ # aws services. Inside these folders
β”‚ # are Lambda handlers and other relevant
β”‚ # source code.
β”‚ #
β”‚ # Make sure the services are created
β”‚ # as "npm" packages so that they have
β”‚ # package.json and tsconfig.ts files.
└── stacks
└── # Here goes AWS stacks definitions.
# One folder for each service.
# Make sure there is always file stack.ts
# inside each folder.
#
# Only individual TS files. No packages.
```

## ENV file

Env file is quite simple in this case. Only `AWS_PROFILE` is necessary value.

### Example

```ini
AWS_PROFILE=purple-technology
```

## Setup

There are some settings which need to be changed in order to make this boilerplate project work.

### GitHub Actions

`.github/workflows/*`

- replace all `CHANGE_ME` values
- `role-session-name` - identifier of the application
- `role-to-assume` - usually apps are deployed to "Production" and "Staging" AWS accounts. `master` branch gets deployed to "Production" and the rest goes to the "Staging" AWS account. Make sure to put there correct deployment roles.
- [How to setup GitHub OpenID Connect on AWS](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services)

### SST config

`sst.config.ts`

- Change app name. Current value: `name: 'purple-stack'`
- Change regions. Current value: `region: stage === 'master' ? 'eu-central-1' : 'eu-central-1'`
- Eventually enable tracing if you need. Current value: `tracing: 'disabled'`

## Best practices

### 1. Separate stateful resources to a separate stack

You can use pre-defined `ResourceStack` for this.

> #### Separate your application into multiple stacks as dictated by deployment requirements
> There is no hard and fast rule to how many stacks your application needs. You'll usually end up basing the decision on your deployment patterns. Keep in mind the following guidelines:
>
> - It's typically more straightforward to keep as many resources in the same stack as possible, so keep them together unless you know you want them separated.
>
> - **Consider keeping stateful resources (like databases) in a separate stack from stateless resources. You can then turn on termination protection on the stateful stack. This way, you can freely destroy or create multiple copies of the stateless stack without risk of data loss.**
>
> - Stateful resources are more sensitive to construct renamingβ€”renaming leads to resource replacement. Therefore, don't nest stateful resources inside constructs that are likely to be moved around or renamed (unless the state can be rebuilt if lost, like a cache). This is another good reason to put stateful resources in their own stack.
Read more [here](https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html#best-practices-apps).

### 2. Don't turn off ESlint and TSconfig rules

The rules are there for a reason. Always make sure to try all possible solutions to comply with the rules before disabling the rule.

Every time you use `any` in the code a bunny dies.

<p align="center">
<img width="250" src="https://github.com/purple-technology/purple-stack/assets/6282843/0f86dd12-436a-4ceb-9bf3-8d2b9d72d93f" />
</p>

### 3. Take advantage of all the features of SST

SST has a lot of great quirks and features like `use`, `bind` etc.

Read their [docs](https://docs.sst.dev/).
12 changes: 12 additions & 0 deletions constructs/ExampleConstruct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Construct } from 'constructs'

export interface ExampleConstructProps {}

export class ExampleConstruct extends Construct {
constructor(scope: Construct, id: string, props: ExampleConstructProps) {
super(scope, id)
// here goes your construct code
// make sure to use "this" when providing "scope" to child constructs
console.log(props)
}
}
1 change: 0 additions & 1 deletion constructs/index.ts

This file was deleted.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@
"console": "pnpm run env -- sst console",
"secrets": "pnpm run env -- sst secrets",
"test": "vitest run",
"test:watch": "vitest"
"test:watch": "vitest",
"typecheck": "tsc --noEmit",
"typecheck:all": "pnpm run env -- pnpm run ci:typecheck:all",
"ci:typecheck:all": "sst build && pnpm run typecheck && pnpm run -r typecheck"
},
"lint-staged": {
"*.{ts,tsx,js,jsx}": "eslint --fix",
"*.{graphql,gql,html,json}": "prettier --write"
},
"devDependencies": {
"semantic-release": "^23.0.0",
"@commitlint/cli": "^18.5.0",
"@commitlint/config-conventional": "^18.5.0",
"@microsoft/eslint-plugin-sdl": "^0.2.2",
Expand Down
3 changes: 3 additions & 0 deletions packages/timestamp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",
"scripts": {
"typecheck": "tsc -noEmit"
},
"devDependencies": {
"vitest": "^1.2.1"
},
Expand Down
Loading

0 comments on commit ea2e909

Please sign in to comment.