From eb3a8a92166629d6a9d144f484a31e1ad0d00446 Mon Sep 17 00:00:00 2001 From: Hakan Shehu Date: Wed, 11 Jun 2025 12:31:52 +0200 Subject: [PATCH] Docker and workflow improvements (#46) --- ...h.yml => server-docker-build-and-push.yml} | 3 +- ...test.yml => server-docker-mark-latest.yml} | 7 +- .../web-cf-build-and-deploy-beta.yml | 81 +++++++++++++++++++ ...loy-cf.yml => web-cf-build-and-deploy.yml} | 5 +- .../workflows/web-docker-build-and-push.yml | 60 ++++++++++++++ .github/workflows/web-docker-mark-latest.yml | 32 ++++++++ apps/server/Dockerfile | 2 +- apps/server/src/lib/config/server.ts | 2 +- apps/web/Dockerfile | 44 ++++++++++ docker-compose.yaml | 10 ++- package-lock.json | 1 + .../src/services/accounts/account-socket.ts | 2 +- 12 files changed, 236 insertions(+), 13 deletions(-) rename .github/workflows/{server-build-and-push.yml => server-docker-build-and-push.yml} (92%) rename .github/workflows/{server-mark-latest.yml => server-docker-mark-latest.yml} (63%) create mode 100644 .github/workflows/web-cf-build-and-deploy-beta.yml rename .github/workflows/{web-build-and-deploy-cf.yml => web-cf-build-and-deploy.yml} (98%) create mode 100644 .github/workflows/web-docker-build-and-push.yml create mode 100644 .github/workflows/web-docker-mark-latest.yml create mode 100644 apps/web/Dockerfile diff --git a/.github/workflows/server-build-and-push.yml b/.github/workflows/server-docker-build-and-push.yml similarity index 92% rename from .github/workflows/server-build-and-push.yml rename to .github/workflows/server-docker-build-and-push.yml index 6719fbc4..5459a3fe 100644 --- a/.github/workflows/server-build-and-push.yml +++ b/.github/workflows/server-docker-build-and-push.yml @@ -7,7 +7,6 @@ on: env: REGISTRY: ghcr.io - SERVER_IMAGE_NAME: colanode/server jobs: build: @@ -55,7 +54,7 @@ jobs: push: true platforms: linux/amd64,linux/arm64 tags: | - ${{ env.REGISTRY }}/${{ env.SERVER_IMAGE_NAME }}:${{ env.VERSION }} + ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:${{ env.VERSION }} labels: | org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} org.opencontainers.image.revision=${{ github.sha }} diff --git a/.github/workflows/server-mark-latest.yml b/.github/workflows/server-docker-mark-latest.yml similarity index 63% rename from .github/workflows/server-mark-latest.yml rename to .github/workflows/server-docker-mark-latest.yml index 82433600..897ae7ed 100644 --- a/.github/workflows/server-mark-latest.yml +++ b/.github/workflows/server-docker-mark-latest.yml @@ -6,7 +6,6 @@ on: env: REGISTRY: ghcr.io - SERVER_IMAGE_NAME: colanode/server jobs: tag-latest: @@ -25,9 +24,9 @@ jobs: run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV - name: Pull version image - run: docker pull ${{ env.REGISTRY }}/${{ env.SERVER_IMAGE_NAME }}:${{ env.VERSION }} + run: docker pull ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:${{ env.VERSION }} - name: Tag and push as latest run: | - docker tag ${{ env.REGISTRY }}/${{ env.SERVER_IMAGE_NAME }}:${{ env.VERSION }} ${{ env.REGISTRY }}/${{ env.SERVER_IMAGE_NAME }}:latest - docker push ${{ env.REGISTRY }}/${{ env.SERVER_IMAGE_NAME }}:latest + docker tag ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:${{ env.VERSION }} ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:latest + docker push ${{ env.REGISTRY }}/${{ vars.SERVER_IMAGE_NAME }}:latest diff --git a/.github/workflows/web-cf-build-and-deploy-beta.yml b/.github/workflows/web-cf-build-and-deploy-beta.yml new file mode 100644 index 00000000..2c63364f --- /dev/null +++ b/.github/workflows/web-cf-build-and-deploy-beta.yml @@ -0,0 +1,81 @@ +name: Build and deploy beta web app to Cloudflare + +on: + push: + tags: + - 'v*' + +jobs: + deploy: + runs-on: ubuntu-latest + name: Deploy + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'npm' + + - name: Get the version + id: get_version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV + + - name: Set version and commit SHA into build.ts + run: | + cat < ./packages/core/src/types/build.ts + // This file is auto-generated during CI/CD + const VERSION = "${{ env.VERSION }}"; + const SHA = "${{ github.sha }}"; + + export const build = { + version: VERSION, + sha: SHA + }; + EOF + + - name: Install dependencies + run: npm ci + + - name: Build packages/core + working-directory: packages/core + run: npm run build + + - name: Build packages/crdt + working-directory: packages/crdt + run: npm run build + + - name: Build packages/client + working-directory: packages/client + run: npm run build + + - name: Build packages/ui + working-directory: packages/ui + run: npm run build + + - name: Build Web App + working-directory: apps/web + run: npm run build + + - name: Create wrangler.jsonc + working-directory: apps/web + run: | + cat > wrangler.jsonc << EOF + { + "name": "${{ secrets.CLOUDFLARE_WORKER_NAME_BETA }}", + "compatibility_date": "2025-05-28", + "assets": { + "directory": "./dist", + "not_found_handling": "single-page-application" + } + } + EOF + + - name: Deploy + uses: cloudflare/wrangler-action@v3 + with: + workingDirectory: ./apps/web + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: deploy diff --git a/.github/workflows/web-build-and-deploy-cf.yml b/.github/workflows/web-cf-build-and-deploy.yml similarity index 98% rename from .github/workflows/web-build-and-deploy-cf.yml rename to .github/workflows/web-cf-build-and-deploy.yml index 86e09d93..ac818023 100644 --- a/.github/workflows/web-build-and-deploy-cf.yml +++ b/.github/workflows/web-cf-build-and-deploy.yml @@ -1,9 +1,8 @@ name: Build and deploy web app to Cloudflare on: - push: - tags: - - 'v*' + release: + types: [published] jobs: deploy: diff --git a/.github/workflows/web-docker-build-and-push.yml b/.github/workflows/web-docker-build-and-push.yml new file mode 100644 index 00000000..5289ce01 --- /dev/null +++ b/.github/workflows/web-docker-build-and-push.yml @@ -0,0 +1,60 @@ +name: Build and push server docker image + +on: + push: + tags: + - 'v*' + +env: + REGISTRY: ghcr.io + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Get the version + id: get_version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV + + - name: Set version and commit SHA into build.ts + run: | + cat < ./packages/core/src/types/build.ts + // This file is auto-generated during CI/CD + const VERSION = "${{ env.VERSION }}"; + const SHA = "${{ github.sha }}"; + + export const build = { + version: VERSION, + sha: SHA + }; + EOF + + - name: Build and push Colanode web image + uses: docker/build-push-action@v5 + with: + context: . + file: ./apps/web/Dockerfile + push: true + platforms: linux/amd64,linux/arm64 + tags: | + ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:${{ env.VERSION }} + labels: | + org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} + org.opencontainers.image.revision=${{ github.sha }} diff --git a/.github/workflows/web-docker-mark-latest.yml b/.github/workflows/web-docker-mark-latest.yml new file mode 100644 index 00000000..160b5db2 --- /dev/null +++ b/.github/workflows/web-docker-mark-latest.yml @@ -0,0 +1,32 @@ +name: Mark web docker image as latest + +on: + release: + types: [published] + +env: + REGISTRY: ghcr.io + +jobs: + tag-latest: + runs-on: ubuntu-latest + + steps: + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Get the version + id: get_version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV + + - name: Pull version image + run: docker pull ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:${{ env.VERSION }} + + - name: Tag and push as latest + run: | + docker tag ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:${{ env.VERSION }} ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:latest + docker push ${{ env.REGISTRY }}/${{ vars.WEB_IMAGE_NAME }}:latest diff --git a/apps/server/Dockerfile b/apps/server/Dockerfile index f3c055d0..a5d392fb 100644 --- a/apps/server/Dockerfile +++ b/apps/server/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-alpine +FROM node:22-alpine WORKDIR /app diff --git a/apps/server/src/lib/config/server.ts b/apps/server/src/lib/config/server.ts index 9ca53246..73a829f6 100644 --- a/apps/server/src/lib/config/server.ts +++ b/apps/server/src/lib/config/server.ts @@ -14,7 +14,7 @@ export const serverConfigSchema = z.object({ pathPrefix: z.string().optional(), cors: z.object({ origin: z.string().default('https://app.colanode.com'), - maxAge: z.number().default(7200), + maxAge: z.coerce.number().default(7200), }), }); diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile new file mode 100644 index 00000000..73ea4832 --- /dev/null +++ b/apps/web/Dockerfile @@ -0,0 +1,44 @@ +FROM node:22-alpine AS build + +WORKDIR /app + +# Copy root workspace files +COPY package.json package-lock.json ./ + +# Copy scripts +COPY ../../scripts scripts + +# Copy all package.json files first +COPY ../../packages/core/package.json packages/core/package.json +COPY ../../packages/crdt/package.json packages/crdt/package.json +COPY ../../packages/client/package.json packages/client/package.json +COPY ../../packages/ui/package.json packages/ui/package.json +COPY ../../apps/web/package.json apps/web/package.json + +# Install dependencies +RUN npm ci + +# Copy source files +COPY ../../packages/core packages/core +COPY ../../packages/crdt packages/crdt +COPY ../../packages/client packages/client +COPY ../../packages/ui packages/ui +COPY ../../apps/web apps/web +COPY ../../tsconfig.base.json ./ + +# Build packages +RUN npm run build -w @colanode/core && \ + npm run build -w @colanode/crdt && \ + npm run build -w @colanode/client && \ + npm run build -w @colanode/ui && \ + npm run build -w @colanode/web && \ + npm prune --production + + +FROM nginx:1.27-alpine + +COPY --from=build /app/apps/web/dist /usr/share/nginx/html + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/docker-compose.yaml b/docker-compose.yaml index ddc3f538..35600d7f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -84,7 +84,6 @@ services: # General Node/Server Config # ─────────────────────────────────────────────────────────────── NODE_ENV: production - PORT: 3000 # The server requires a name and avatar URL which will be displayed in the desktop app login screen. SERVER_NAME: 'Colanode Local' @@ -188,6 +187,15 @@ services: networks: - colanode_network + web: + image: ghcr.io/colanode/web:latest + container_name: colanode_web + restart: always + ports: + - '4000:80' + networks: + - colanode_network + volumes: postgres_data: valkey_data: diff --git a/package-lock.json b/package-lock.json index d93fb4cf..270758b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "apps/desktop": { "name": "@colanode/desktop", "version": "1.0.0", + "hasInstallScript": true, "dependencies": { "@colanode/client": "*", "@colanode/core": "*", diff --git a/packages/client/src/services/accounts/account-socket.ts b/packages/client/src/services/accounts/account-socket.ts index 32d3920f..fed31526 100644 --- a/packages/client/src/services/accounts/account-socket.ts +++ b/packages/client/src/services/accounts/account-socket.ts @@ -66,7 +66,7 @@ export class AccountSocket { `${this.account.server.socketBaseUrl}/v1/sockets/${response.id}` ); - this.socket.onmessage = async (event) => { + this.socket.onmessage = async (event: WebSocket.MessageEvent) => { const data: string = event.data.toString(); const message: Message = JSON.parse(data);