mirror of
https://fast.feibisi.com/https://github.com/parcelvoy/platform.git
synced 2025-08-28 11:46:02 +08:00
Adds Docker Jobs (#63)
* Start creating action release flow * Updates build workflow * Removes one step * Another try * Tweaks to build paths * Fixes docker ignore * Tweaks to database migration * Removes useless entrypoint * Fixes to database files * More tweaks to build * Tweaks to base URL * Allows for config file to override env * Tweak to order * Next try * Fixes comma error * Another try * Adds a health endpoint * Try Nginx proxy pass * Re-adds environment path * Remove auto build on branch * Linter fixes
This commit is contained in:
parent
8068d4d586
commit
732d8d1f12
20 changed files with 236 additions and 34 deletions
|
@ -2,4 +2,5 @@
|
|||
.DS_Store
|
||||
.env
|
||||
node_modules
|
||||
**/node_modules
|
||||
build
|
35
.github/workflows/build.yml
vendored
Normal file
35
.github/workflows/build.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
name: Create & Publish Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log In to the Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build the Docker Image
|
||||
run: |
|
||||
npm run docker:build:push
|
109
apps/platform/.gitignore
vendored
Normal file
109
apps/platform/.gitignore
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
*.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
build
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# VS Code
|
||||
.DS_Store
|
|
@ -22,7 +22,5 @@ ENV NODE_ENV="production"
|
|||
USER node
|
||||
WORKDIR /usr/src/app
|
||||
COPY --chown=node:node --from=build /usr/src/app ./
|
||||
RUN chmod 755 ./scripts/entrypoint.sh
|
||||
EXPOSE 3001
|
||||
ENTRYPOINT ["./scripts/entrypoint.sh", "--"]
|
||||
CMD ["dumb-init", "node", "index.js"]
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
"build": "tsc --build",
|
||||
"lint": "eslint --ext .ts --max-warnings 0 src/",
|
||||
"test": "jest --forceExit --testTimeout 10000",
|
||||
"docker:build": "docker buildx build -f ./Dockerfile -t ghcr.io/parcelvoy/api:latest ../../",
|
||||
"docker:build:push": "npm run docker:build -- --push",
|
||||
"migration:create": "node ./scripts/create-migration.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
## Migrate the database
|
||||
node ./migrate.js latest
|
||||
|
||||
# Hand off to the CMD
|
||||
exec "$@"
|
|
@ -1,5 +1,5 @@
|
|||
import Api from './api'
|
||||
import loadDatabase, { Database, migrate } from './config/database'
|
||||
import loadDatabase, { Database } from './config/database'
|
||||
import loadQueue from './config/queue'
|
||||
import loadStorage from './config/storage'
|
||||
import loadAuth from './config/auth'
|
||||
|
@ -20,11 +20,8 @@ export default class App {
|
|||
}
|
||||
|
||||
static async init(env: Env): Promise<App> {
|
||||
// Load database
|
||||
const database = loadDatabase(env.db)
|
||||
|
||||
// Migrate to latest version
|
||||
await migrate(database)
|
||||
// Load & migrate database
|
||||
const database = await loadDatabase(env.db)
|
||||
|
||||
// Load queue
|
||||
const queue = loadQueue(env.queue)
|
||||
|
|
|
@ -106,6 +106,13 @@ export const clientRouter = () => {
|
|||
*/
|
||||
export const publicRouter = () => {
|
||||
const router = new Router()
|
||||
router.get('/health', async (ctx) => {
|
||||
ctx.body = {
|
||||
status: 'ok',
|
||||
environment: process.env.NODE_ENV,
|
||||
time: new Date(),
|
||||
}
|
||||
})
|
||||
return register(router,
|
||||
AuthController,
|
||||
PublicSubscriptionController,
|
||||
|
|
|
@ -7,7 +7,7 @@ export interface DatabaseConnection {
|
|||
port: number
|
||||
user: string
|
||||
password: string
|
||||
database: string
|
||||
database?: string
|
||||
}
|
||||
|
||||
export interface DatabaseConfig {
|
||||
|
@ -15,11 +15,15 @@ export interface DatabaseConfig {
|
|||
connection: DatabaseConnection
|
||||
}
|
||||
|
||||
export default (config: DatabaseConfig) => {
|
||||
const connect = (config: DatabaseConfig, withDB = true) => {
|
||||
const connection = config.connection
|
||||
if (!withDB) {
|
||||
delete connection.database
|
||||
}
|
||||
return knex({
|
||||
client: config.client,
|
||||
connection: {
|
||||
...config.connection,
|
||||
...connection,
|
||||
typeCast(field: any, next: any) {
|
||||
if (field.type === 'TINY' && field.length === 1) {
|
||||
return field.string() === '1'
|
||||
|
@ -31,9 +35,25 @@ export default (config: DatabaseConfig) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const migrate = async (db: Database) => {
|
||||
const migrate = async (db: Database) => {
|
||||
return db.migrate.latest({
|
||||
directory: './db/migrations',
|
||||
tableName: 'migrations',
|
||||
})
|
||||
}
|
||||
|
||||
export default async (config: DatabaseConfig) => {
|
||||
|
||||
// Attempt to connect & migrate
|
||||
try {
|
||||
const db = connect(config)
|
||||
await migrate(db)
|
||||
return db
|
||||
} catch (error) {
|
||||
|
||||
// On error, try to create the database and try again
|
||||
const db = connect(config, false)
|
||||
db.raw('CREATE DATABASE parcelvoy')
|
||||
return connect(config)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ export const capitalizeAll = function(str: string): string {
|
|||
|
||||
/**
|
||||
* Truncates a string to the specified `length`, and appends
|
||||
* it with an elipsis, `…`.
|
||||
* it with an ellipsis, `…`.
|
||||
*/
|
||||
export const ellipsis = function(str: string, limit: number): string {
|
||||
if (!isString(str)) return ''
|
||||
|
|
|
@ -5,5 +5,14 @@
|
|||
"moduleResolution": "node",
|
||||
"baseUrl": "./src",
|
||||
"outDir": "./build"
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"./**/*.spec.ts",
|
||||
"./**/__mocks__/*"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -8,6 +8,11 @@ RUN npm run build
|
|||
|
||||
# --------------> The production image
|
||||
FROM nginx:1.23.1-alpine
|
||||
EXPOSE 80
|
||||
EXPOSE 3000
|
||||
COPY --from=compile /usr/src/app/apps/ui/docker/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=compile /usr/src/app/apps/ui/build /usr/share/nginx/html
|
||||
COPY --from=compile /usr/src/app/apps/ui/build /usr/share/nginx/html
|
||||
COPY --from=compile /usr/src/app/apps/ui/scripts /usr/share/nginx/html
|
||||
WORKDIR /usr/share/nginx/html
|
||||
RUN apk add --no-cache bash
|
||||
RUN chmod +x env.sh
|
||||
CMD ["/bin/bash", "-c", "/usr/share/nginx/html/env.sh && nginx -g \"daemon off;\""]
|
|
@ -1,9 +1,13 @@
|
|||
server {
|
||||
listen 80;
|
||||
listen 3000;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api {
|
||||
proxy_pass http://api:3001;
|
||||
}
|
||||
}
|
|
@ -39,7 +39,9 @@
|
|||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\""
|
||||
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
|
||||
"docker:build": "docker buildx build -f ./Dockerfile -t ghcr.io/parcelvoy/ui:latest ../../",
|
||||
"docker:build:push": "npm run docker:build -- --push"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
1
apps/ui/public/config.js
Normal file
1
apps/ui/public/config.js
Normal file
|
@ -0,0 +1 @@
|
|||
window.API_BASE_URL = undefined
|
|
@ -12,6 +12,8 @@
|
|||
<meta property="og:description" content="Parcelvoy is an open sourced automated messaging and customer engagement tool for growth companies and enterprise alike. Send data-driven emails, push notifications, and SMS using the tools you already use and love." />
|
||||
<meta property="og:url" content="https://parcelvoy.com" />
|
||||
<meta property="og:image" content="https://parcelvoy.com/og-image.jpg" />
|
||||
|
||||
<script src="%PUBLIC_URL%/config.js"></script>
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
|
|
10
apps/ui/scripts/env.sh
Normal file
10
apps/ui/scripts/env.sh
Normal file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
ENV_JS="./config.js"
|
||||
|
||||
rm -rf ${ENV_JS}
|
||||
touch ${ENV_JS}
|
||||
|
||||
varname='API_BASE_URL'
|
||||
value=$(printf '%s\n' "${!varname}")
|
||||
echo "window.$varname = \"$value\";" >> ${ENV_JS}
|
|
@ -1,5 +1,9 @@
|
|||
declare global {
|
||||
interface Window { API_BASE_URL: string }
|
||||
}
|
||||
|
||||
export const env = {
|
||||
api: {
|
||||
baseURL: process.env.REACT_APP_API_BASE_URL!,
|
||||
baseURL: window.API_BASE_URL ?? process.env.REACT_APP_API_BASE_URL,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ services:
|
|||
- mysql_data:/var/lib/mysql
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: "/usr/bin/mysql hallow --user=root --password=$$MYSQL_ROOT_PASSWORD --execute 'SELECT 1;'"
|
||||
test: "/usr/bin/mysql parcelvoy --user=root --password=$$MYSQL_ROOT_PASSWORD --execute 'SELECT 1;'"
|
||||
interval: 1s
|
||||
retries: 120
|
||||
api:
|
||||
image: 'parcelvoy/platform/api:0.1.0'
|
||||
image: 'ghcr.io/parcelvoy/api:latest'
|
||||
restart: always
|
||||
ports:
|
||||
- 3001:3001
|
||||
|
@ -35,6 +35,9 @@ services:
|
|||
DB_PASSWORD: ${DB_PASSWORD}
|
||||
DB_PORT: 3306
|
||||
DB_DATABASE: ${DB_DATABASE}
|
||||
STORAGE_DRIVER: ${STORAGE_DRIVER}
|
||||
STORAGE_BASE_URL: ${STORAGE_BASE_URL}
|
||||
AWS_S3_BUCKET: ${AWS_S3_BUCKET}
|
||||
QUEUE_DRIVER: ${QUEUE_DRIVER}
|
||||
AWS_SQS_QUEUE_URL: ${AWS_SQS_QUEUE_URL}
|
||||
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
|
||||
|
@ -52,15 +55,13 @@ services:
|
|||
AUTH_OPENID_REDIRECT_URI: ${AUTH_OPENID_REDIRECT_URI}
|
||||
AUTH_OPENID_DOMAIN_WHITELIST: ${AUTH_OPENID_DOMAIN_WHITELIST}
|
||||
ui:
|
||||
image: 'parcelvoy/platform/ui:0.1.0'
|
||||
image: 'ghcr.io/parcelvoy/ui:latest'
|
||||
depends_on:
|
||||
- api
|
||||
environment:
|
||||
REACT_APP_API_URL: ${BASE_URL}
|
||||
REACT_APP_ENVIRONMENT: ${NODE_ENV}
|
||||
REACT_APP_DOCKER_HOSTED_ENV: 'true'
|
||||
API_BASE_URL: ${API_BASE_URL}
|
||||
ports:
|
||||
- 3000:3000
|
||||
- 80:3000
|
||||
volumes:
|
||||
mysql_data:
|
||||
driver: local
|
|
@ -11,6 +11,8 @@
|
|||
"start": "lerna run start",
|
||||
"build": "lerna run build",
|
||||
"lint": "lerna run lint",
|
||||
"test": "lerna run test"
|
||||
"test": "lerna run test",
|
||||
"docker:build": "lerna run docker:build",
|
||||
"docker:build:push": "lerna run docker:build:push"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue