From 2d64815c12b88bbb6687dbddb163568e17a38e87 Mon Sep 17 00:00:00 2001 From: Krzysztof Durek <21038648+kdurek@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:05:27 +0200 Subject: [PATCH 01/12] fix: disable husky only on production --- .github/workflows/pull-request.yml | 2 ++ .husky/install.mjs | 6 ++++++ Dockerfile | 8 +++++++- package.json | 3 ++- 4 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 .husky/install.mjs diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 278059732..5f8130bb6 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -9,6 +9,8 @@ on: branches: - main - canary +env: + HUSKY: 0 jobs: build-app: if: github.event_name == 'pull_request' diff --git a/.husky/install.mjs b/.husky/install.mjs new file mode 100644 index 000000000..9b13ce1f9 --- /dev/null +++ b/.husky/install.mjs @@ -0,0 +1,6 @@ +// Skip Husky install in production and CI +if (process.env.NODE_ENV === "production" || process.env.CI === "true") { + process.exit(0); +} +const husky = (await import("husky")).default; +console.log(husky()); diff --git a/Dockerfile b/Dockerfile index 6d3e58758..11b66bde4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,9 @@ # Etapa 1: Prepare image for building FROM node:18-slim AS base +# Disable husky +ENV HUSKY=0 + # Install dependencies ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" @@ -23,6 +26,9 @@ RUN pnpm run build # Stage 2: Prepare image for production FROM node:18-slim AS production +# Disable husky +ENV HUSKY=0 + # Install dependencies only for production ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" @@ -61,4 +67,4 @@ RUN curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.32.1/pack # Expose port EXPOSE 3000 -CMD ["pnpm", "start"] \ No newline at end of file +CMD ["pnpm", "start"] diff --git a/package.json b/package.json index 354d85afe..8d55f9478 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "docker:build:canary": "./docker/build.sh canary", "docker:push:canary": "./docker/push.sh canary", "version": "echo $(node -p \"require('./package.json').version\")", - "test": "vitest --config __test__/vitest.config.ts" + "test": "vitest --config __test__/vitest.config.ts", + "prepare": "node .husky/install.mjs" }, "dependencies": { "@aws-sdk/client-s3": "3.515.0", From e249e878f6c8bcfca7c368de4af8847e7ad1b81b Mon Sep 17 00:00:00 2001 From: Krzysztof Durek <21038648+kdurek@users.noreply.github.com> Date: Tue, 16 Jul 2024 14:11:44 +0200 Subject: [PATCH 02/12] fix: disable husky only on production --- Dockerfile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 11b66bde4..2b2a1ca80 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,6 @@ # Etapa 1: Prepare image for building FROM node:18-slim AS base -# Disable husky -ENV HUSKY=0 - # Install dependencies ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" @@ -11,6 +8,10 @@ RUN corepack enable && apt-get update && apt-get install -y python3 make g++ git WORKDIR /app +# Disable husky +ENV HUSKY=0 +COPY .husky/install.mjs ./.husky/install.mjs + # Copy package.json and pnpm-lock.yaml COPY package.json pnpm-lock.yaml ./ @@ -36,6 +37,12 @@ RUN corepack enable && apt-get update && apt-get install -y curl && apt-get inst WORKDIR /app +ENV NODE_ENV production + +# Disable husky +ENV HUSKY=0 +COPY --from=base /app/.husky/install.mjs ./.husky/install.mjs + # Copy the rest of the source code COPY --from=base /app/.next ./.next COPY --from=base /app/dist ./dist From c0587b9409c06bb68ee34b4e4627b1990b3f38da Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:45:41 -0600 Subject: [PATCH 03/12] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 97379020e..e405a0094 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +github: [siumauricio] patreon: # open_collective: dokploy ko_fi: # Replace with a single Ko-fi username From 38c16fe8398f83675c0afdde83ffc54ec4fca34b Mon Sep 17 00:00:00 2001 From: "Anh (Daniel) Le" Date: Wed, 17 Jul 2024 14:59:16 +0700 Subject: [PATCH 04/12] feat: add copy function to visibility input --- components/shared/toggle-visibility-input.tsx | 56 ++++++++++++------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/components/shared/toggle-visibility-input.tsx b/components/shared/toggle-visibility-input.tsx index aef09880e..078a2f264 100644 --- a/components/shared/toggle-visibility-input.tsx +++ b/components/shared/toggle-visibility-input.tsx @@ -1,26 +1,44 @@ -import { EyeIcon, EyeOffIcon } from "lucide-react"; -import { useState } from "react"; +import { EyeIcon, EyeOffIcon, Clipboard } from "lucide-react"; +import { useRef, useState } from "react"; import { Button } from "../ui/button"; import { Input, type InputProps } from "../ui/input"; +import { toast } from "sonner"; export const ToggleVisibilityInput = ({ ...props }: InputProps) => { - const [isPasswordVisible, setIsPasswordVisible] = useState(false); + const [isPasswordVisible, setIsPasswordVisible] = useState(false); + const inputRef = useRef(null) - const togglePasswordVisibility = () => { - setIsPasswordVisible((prevVisibility) => !prevVisibility); - }; + const togglePasswordVisibility = () => { + setIsPasswordVisible((prevVisibility) => !prevVisibility); + }; - const inputType = isPasswordVisible ? "text" : "password"; - return ( -
- - -
- ); + const copyToClipboard = () => { + if (!inputRef.current) return; + + const inputElement = inputRef.current; + const text = inputElement.value; + + inputElement.select(); + inputElement.setSelectionRange(0, 99999); + navigator.clipboard.writeText(text); + + toast.success("Value is copied to clipboard"); + } + + const inputType = isPasswordVisible ? "text" : "password"; + return ( +
+ + + +
+ ); }; From 95246090920588223f6db4c81634ceedc4162a8d Mon Sep 17 00:00:00 2001 From: Krzysztof Durek <21038648+kdurek@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:32:33 +0200 Subject: [PATCH 05/12] ci: split workflows to separate files --- .github/workflows/pull-request.yml | 34 ++++------------------------- .github/workflows/push.yml | 35 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/push.yml diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 278059732..97fffc7f7 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -1,17 +1,16 @@ name: Pull request + on: pull_request: branches: - main - canary - push: - branches: - - main - - canary +env: + HUSKY: 0 + jobs: build-app: - if: github.event_name == 'pull_request' runs-on: ubuntu-latest strategy: matrix: @@ -45,28 +44,3 @@ jobs: - name: Run Tests run: pnpm run test - - build-and-push-docker-on-push: - if: github.event_name == 'push' - runs-on: ubuntu-latest - steps: - - name: Check out the code - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Prepare .env file - run: | - cp .env.production.example .env.production - - - name: Build and push Docker image using custom script - run: | - chmod +x ./docker/push.sh - ./docker/push.sh ${{ github.ref_name == 'canary' && 'canary' || '' }} diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 000000000..1534e6d28 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,35 @@ +name: Push + +on: + push: + branches: + - main + - canary + +env: + HUSKY: 0 + +jobs: + build-and-push-docker-on-push: + runs-on: ubuntu-latest + steps: + - name: Check out the code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Prepare .env file + run: | + cp .env.production.example .env.production + + - name: Build and push Docker image using custom script + run: | + chmod +x ./docker/push.sh + ./docker/push.sh ${{ github.ref_name == 'canary' && 'canary' || '' }} From 35652c5c53ffbada150c51a203a044f796aa6a3b Mon Sep 17 00:00:00 2001 From: Krzysztof Durek <21038648+kdurek@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:33:21 +0200 Subject: [PATCH 06/12] build: split build into multiple stages for caching --- Dockerfile | 70 ++++++++++++++++++++++++++++++++-------------------- package.json | 1 + 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6d3e58758..8075325cb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,48 +1,65 @@ -# Etapa 1: Prepare image for building FROM node:18-slim AS base -# Install dependencies +# Disable husky +ENV HUSKY=0 + +# Set pnpm home ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" -RUN corepack enable && apt-get update && apt-get install -y python3 make g++ git && rm -rf /var/lib/apt/lists/* +# Enable corepack +RUN corepack enable + +# Set workdir WORKDIR /app +FROM base AS base-deps +# Install dependencies only for production +RUN apt-get update && apt-get install -y python3 make g++ git && rm -rf /var/lib/apt/lists/* + +# Copy install script for husky +COPY .husky/install.mjs ./.husky/install.mjs + # Copy package.json and pnpm-lock.yaml COPY package.json pnpm-lock.yaml ./ +FROM base-deps AS prod-deps + +# Set production +ENV NODE_ENV=production + +# Install dependencies only for production +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile + +FROM base-deps AS build + # Install dependencies only for building RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile # Copy the rest of the source code COPY . . -# Build the application -RUN pnpm run build +# Build the application +RUN pnpm build -# Stage 2: Prepare image for production -FROM node:18-slim AS production +FROM base AS production + +# Set production +ENV NODE_ENV=production # Install dependencies only for production -ENV PNPM_HOME="/pnpm" -ENV PATH="$PNPM_HOME:$PATH" -RUN corepack enable && apt-get update && apt-get install -y curl && apt-get install -y apache2-utils && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y curl apache2-utils && rm -rf /var/lib/apt/lists/* -WORKDIR /app - -# Copy the rest of the source code -COPY --from=base /app/.next ./.next -COPY --from=base /app/dist ./dist -COPY --from=base /app/next.config.mjs ./next.config.mjs -COPY --from=base /app/public ./public -COPY --from=base /app/package.json ./package.json -COPY --from=base /app/drizzle ./drizzle -COPY --from=base /app/.env.production ./.env -COPY --from=base /app/components.json ./components.json - -# Install dependencies only for production -COPY package.json pnpm-lock.yaml ./ -RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile +# Copy the rest of the source code +COPY --from=build /app/.next ./.next +COPY --from=build /app/dist ./dist +COPY --from=build /app/next.config.mjs ./next.config.mjs +COPY --from=build /app/public ./public +COPY --from=build /app/package.json ./package.json +COPY --from=build /app/drizzle ./drizzle +COPY --from=build /app/.env.production ./.env +COPY --from=build /app/components.json ./components.json +COPY --from=prod-deps /app/node_modules ./node_modules # Install docker RUN curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh && rm get-docker.sh @@ -54,11 +71,10 @@ RUN curl -sSL https://nixpacks.com/install.sh -o install.sh \ && ./install.sh \ && pnpm install -g tsx - # Install buildpacks RUN curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.32.1/pack-v0.32.1-linux.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack # Expose port EXPOSE 3000 -CMD ["pnpm", "start"] \ No newline at end of file +CMD ["pnpm", "start"] diff --git a/package.json b/package.json index 354d85afe..32db5718e 100644 --- a/package.json +++ b/package.json @@ -157,6 +157,7 @@ "ct3aMetadata": { "initVersion": "7.25.2" }, + "packageManager": "pnpm@8.15.4", "engines": { "node": "^18.18.0", "pnpm": ">=8.15.4" From 1befdb76e77d883049c24eb7a55aa79a0ffd20d9 Mon Sep 17 00:00:00 2001 From: Krzysztof Durek <21038648+kdurek@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:38:49 +0200 Subject: [PATCH 07/12] ci: pnpm gets version from package.json packageManager field --- .github/workflows/pull-request.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 97fffc7f7..81910e63b 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -21,8 +21,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 - with: - version: 8 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 From c3bca21d144fc73dd13e347f364a9924d8cd52c4 Mon Sep 17 00:00:00 2001 From: "Anh (Daniel) Le" Date: Wed, 17 Jul 2024 18:55:40 +0700 Subject: [PATCH 08/12] fix: remove redundant selection api --- components/shared/toggle-visibility-input.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/shared/toggle-visibility-input.tsx b/components/shared/toggle-visibility-input.tsx index 078a2f264..bda228bcc 100644 --- a/components/shared/toggle-visibility-input.tsx +++ b/components/shared/toggle-visibility-input.tsx @@ -19,7 +19,6 @@ export const ToggleVisibilityInput = ({ ...props }: InputProps) => { const text = inputElement.value; inputElement.select(); - inputElement.setSelectionRange(0, 99999); navigator.clipboard.writeText(text); toast.success("Value is copied to clipboard"); From e4c243d7a696dc1c8256b9f0c36b507c56640499 Mon Sep 17 00:00:00 2001 From: "Anh (Daniel) Le" Date: Thu, 18 Jul 2024 00:15:43 +0700 Subject: [PATCH 09/12] fix: format toggle visibility input --- components/shared/toggle-visibility-input.tsx | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/components/shared/toggle-visibility-input.tsx b/components/shared/toggle-visibility-input.tsx index bda228bcc..04cebaad7 100644 --- a/components/shared/toggle-visibility-input.tsx +++ b/components/shared/toggle-visibility-input.tsx @@ -5,39 +5,39 @@ import { Input, type InputProps } from "../ui/input"; import { toast } from "sonner"; export const ToggleVisibilityInput = ({ ...props }: InputProps) => { - const [isPasswordVisible, setIsPasswordVisible] = useState(false); - const inputRef = useRef(null) + const [isPasswordVisible, setIsPasswordVisible] = useState(false); + const inputRef = useRef(null); - const togglePasswordVisibility = () => { - setIsPasswordVisible((prevVisibility) => !prevVisibility); - }; + const togglePasswordVisibility = () => { + setIsPasswordVisible((prevVisibility) => !prevVisibility); + }; - const copyToClipboard = () => { - if (!inputRef.current) return; + const copyToClipboard = () => { + if (!inputRef.current) return; - const inputElement = inputRef.current; - const text = inputElement.value; + const inputElement = inputRef.current; + const text = inputElement.value; - inputElement.select(); - navigator.clipboard.writeText(text); + inputElement.select(); + navigator.clipboard.writeText(text); - toast.success("Value is copied to clipboard"); - } + toast.success("Value is copied to clipboard"); + }; - const inputType = isPasswordVisible ? "text" : "password"; - return ( -
- - - -
- ); + const inputType = isPasswordVisible ? "text" : "password"; + return ( +
+ + + +
+ ); }; From 87e90cb30b976ae91752db5a71777afeca4641af Mon Sep 17 00:00:00 2001 From: "Anh (Daniel) Le" Date: Thu, 18 Jul 2024 09:44:45 +0700 Subject: [PATCH 10/12] fix: use copy-to-clipboard for visibility input --- components/shared/toggle-visibility-input.tsx | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/components/shared/toggle-visibility-input.tsx b/components/shared/toggle-visibility-input.tsx index 04cebaad7..bb11eeaef 100644 --- a/components/shared/toggle-visibility-input.tsx +++ b/components/shared/toggle-visibility-input.tsx @@ -1,8 +1,9 @@ -import { EyeIcon, EyeOffIcon, Clipboard } from "lucide-react"; +import copy from "copy-to-clipboard"; +import { Clipboard, EyeIcon, EyeOffIcon } from "lucide-react"; import { useRef, useState } from "react"; +import { toast } from "sonner"; import { Button } from "../ui/button"; import { Input, type InputProps } from "../ui/input"; -import { toast } from "sonner"; export const ToggleVisibilityInput = ({ ...props }: InputProps) => { const [isPasswordVisible, setIsPasswordVisible] = useState(false); @@ -12,23 +13,17 @@ export const ToggleVisibilityInput = ({ ...props }: InputProps) => { setIsPasswordVisible((prevVisibility) => !prevVisibility); }; - const copyToClipboard = () => { - if (!inputRef.current) return; - - const inputElement = inputRef.current; - const text = inputElement.value; - - inputElement.select(); - navigator.clipboard.writeText(text); - - toast.success("Value is copied to clipboard"); - }; - const inputType = isPasswordVisible ? "text" : "password"; return (
-