Skip to content

Commit

Permalink
ready for deployment
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <timo@animo.id>
  • Loading branch information
TimoGlastra committed Jan 12, 2024
1 parent 61ab8c6 commit 300fb77
Show file tree
Hide file tree
Showing 17 changed files with 11,527 additions and 177 deletions.
133 changes: 133 additions & 0 deletions .github/workflows/continuous_deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
name: Continuous Deployment

on:
workflow_dispatch:
inputs:
build:
default: true
type: boolean
required: false
description: Build the website before deploying
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
SERVER: server
CLIENT: client

jobs:
build-and-push-image-server:
runs-on: ubuntu-latest
if: inputs.build == true && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write

defaults:
run:
working-directory: packages/${{ env.SERVER }}

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

- name: Log in to the Container registry
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.SERVER }}

- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: ./packages/server
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

build-and-push-image-client:
runs-on: ubuntu-latest
if: inputs.build == true && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write

defaults:
run:
working-directory: packages/${{ env.CLIENT }}

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

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

- name: Install dependencies
run: pnpm install --no-frozen-lockfile

- run: VITE_API_URL=https://snake-demo-server.paradym.id pnpm build

- name: Log in to the Container registry
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.CLIENT }}

- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: ./packages/client
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

deploy:
# Only run on main branch
runs-on: ubuntu-latest
needs: [build-and-push-image-server, build-and-push-image-client]
if: |
always() &&
(needs.build-and-push-image-server.result == 'success' || needs.build-and-push-image-server.result == 'skipped') &&
(needs.build-and-push-image-client.result == 'success' || needs.build-and-push-image-client.result == 'skipped') &&
github.ref == 'refs/heads/main'
steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Copy stack file to remote
uses: garygrossgarten/github-action-scp@v0.7.3
with:
local: docker-compose.yml
remote: paradym-snake-demo/docker-compose.yml
host: dashboard.dev.animo.id
username: root
privateKey: ${{ secrets.DOCKER_SSH_PRIVATE_KEY }}

- name: Deploy to Docker Swarm via SSH action
uses: appleboy/ssh-action@v0.1.4
env:
PARADYM_API_KEY: ${{ secrets.PARADYM_API_KEY }}
PARADYM_WORKFLOW_ID: ${{ vars.PARADYM_WORKFLOW_ID }}
PARADYM_HMAC_SIGNATURE: ${{ secrets.PARADYM_HMAC_SIGNATURE }}
with:
host: dashboard.dev.animo.id
username: root
key: ${{ secrets.DOCKER_SSH_PRIVATE_KEY }}
envs: PARADYM_API_KEY,PARADYM_WORKFLOW_ID,PARADYM_HMAC_SIGNATURE
script: |
PARADYM_HMAC_SIGNATURE=${PARADYM_HMAC_SIGNATURE} PARADYM_WORKFLOW_ID=${PARADYM_WORKFLOW_ID} PARADYM_API_KEY=${PARADYM_API_KEY} docker stack deploy --compose-file paradym-snake-demo/docker-compose.yml paradym-snake-demo --with-registry-auth
58 changes: 58 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
version: "3.5"

services:
server:
image: ghcr.io/animo/paradym-example-achievement-credential/server:main
deploy:
placement:
constraints:
- node.role == worker
- node.labels.type == community
labels:
traefik.enable: "true"

traefik.http.routers.snake-demo-server.rule: Host(`snake-demo-server.paradym.id`)
traefik.http.routers.snake-demo-server.entrypoints: web-secure
traefik.http.routers.snake-demo-server.tls.certresolver: zerossl
traefik.http.routers.snake-demo-server.service: snake-demo-server-service
traefik.http.services.snake-demo-server-service.loadbalancer.server.port: 5000

environment:
PARADYM_API_KEY: ${PARADYM_API_KEY}
PARADYM_HMAC_SIGNATURE: ${PARADYM_HMAC_SIGNATURE}
PARADYM_WORKFLOW_ID: ${PARADYM_WORKFLOW_ID}
PORT: 5000

networks:
- traefik

ports:
- 5000

client:
image: ghcr.io/animo/paradym-example-achievement-credential/client:main
deploy:
placement:
constraints:
- node.role == worker
- node.labels.type == community
labels:
traefik.enable: "true"
traefik.http.routers.snake-demo.rule: Host(`snake-demo.paradym.id`)
traefik.http.routers.snake-demo.entrypoints: web-secure
traefik.http.routers.snake-demo.tls.certresolver: zerossl
traefik.http.routers.snake-demo.service: snake-demo-service
traefik.http.services.snake-demo-service.loadbalancer.server.port: 80
update_config:
monitor: 30s
delay: 10s
order: start-first
ports:
- 80
networks:
- traefik

networks:
traefik:
external: true
name: traefik
6 changes: 6 additions & 0 deletions packages/client/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM nginx

COPY ./dist /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
9 changes: 6 additions & 3 deletions packages/client/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link href='https://fonts.googleapis.com/css?family=Inter' rel='stylesheet'>
<link
href="https://fonts.googleapis.com/css?family=Inter"
rel="stylesheet"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<title>Paradym Snake Demo</title>
</head>
<body>
<div id="root"></div>
Expand Down
15 changes: 15 additions & 0 deletions packages/client/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;

location / {
try_files $uri $uri/ /index.html;
}

# Any route containing a file extension (e.g. /devicesfile.js)
location ~ ^.+\..+$ {
try_files $uri =404;
}
}
30 changes: 0 additions & 30 deletions packages/client/src/GameLogic.ts

This file was deleted.

34 changes: 0 additions & 34 deletions packages/client/src/Snake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,6 @@ export class Snake {
this.gridSize = gridSize;
}

private getHead() {
return this.bodyParts[0];
}

private checkSelfCollision() {
const head = this.getHead();
for (let i = 1; i < this.bodyParts.length; i++) {
if (this.bodyParts[i].x === head.x && this.bodyParts[i].y === head.y) {
return true;
}
}
return false;
}

private checkWallCollision(gameArea: Vector) {
const head = this.getHead();
if (
head.x < 0 ||
head.y < 0 ||
head.x >= gameArea.x ||
head.y >= gameArea.y
)
return true;
return false;
}

private checkFoodCollision(food: Vector) {
const head = this.getHead();
if (head.x === food.x && head.y === food.y) {
return true;
}
return false;
}

private getNewSnakePosition(direction: Vector) {
return this.bodyParts.map((segment, index) => {
if (index === 0) {
Expand Down
6 changes: 3 additions & 3 deletions packages/client/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
const url = "http://localhost:3000";
const API_URL = import.meta.env.VITE_API_URL ?? "http://localhost:3000";

export const fetchHighScoreFromAPI = async () => {
const response = await fetch(`${url}/highscore`);
const response = await fetch(`${API_URL}/highscore`);
const data = await response.json();
return data;
};

export const postScoreToAPI = async (score: number) => {
const response = await fetch(`${url}/highscore`, {
const response = await fetch(`${API_URL}/highscore`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Expand Down
1 change: 0 additions & 1 deletion packages/client/src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from "react";
import { GameBoard } from "./GameBoard";

export const App = () => {
Expand Down
12 changes: 6 additions & 6 deletions packages/client/src/components/GameBoard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
import React, {
import {
useState,
useRef,
useEffect,
Expand All @@ -10,7 +10,7 @@ import React, {
import { fetchHighScoreFromAPI, postScoreToAPI } from "../api";
import "./GameBoard.css";
import { GameOverOverlay } from "./GameOverOverlay";
import {Snake } from './Snake'

export const GameBoard = () => {
const canvasRef = useRef<HTMLCanvasElement>(null);

Expand All @@ -20,7 +20,6 @@ export const GameBoard = () => {
}>({ highscore: 0, currentScore: 0 });

const [gameOver, setGameOver] = useState(false);
// const [snake, setSnake] = useState<{ top: number; left: number }[]>([]);
const [snake, setSnake] = useState<Snake>();

const [food, setFood] = useState<{ top: number; left: number }>();
Expand Down Expand Up @@ -86,7 +85,8 @@ export const GameBoard = () => {
const canvasWidth = canvasRef.current.width;

// Update the snake's position
setSnake((prevSnake: Snake) => {
setSnake((prevSnake: Snake | undefined) => {
if (!prevSnake) return prevSnake;
const newSnake = calculateNewSnakePosition(
prevSnake,
direction,
Expand Down Expand Up @@ -141,7 +141,7 @@ export const GameBoard = () => {
};

useEffect(() => {
if (food && checkFoodCollision(snake)) {
if (food && checkFoodCollision(snake ?? [])) {
// setScore(score + 1);
setScoreBoard({
...scoreBoard,
Expand Down Expand Up @@ -221,7 +221,7 @@ export const GameBoard = () => {
ctx.fillStyle = "rgba(255, 255, 255, 0.2)";
ctx.fillRect(0, 0, currentRef.width, currentRef.height);
ctx.fillStyle = "green";
snake.forEach((segment) => {
snake?.forEach((segment) => {
ctx.fillRect(segment.left, segment.top, 10, 10);
});
ctx.fillStyle = "red";
Expand Down
Loading

0 comments on commit 300fb77

Please sign in to comment.