diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..d4002e0 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,24 @@ +name: Nx validate CI + +on: + push: + branches: + - master + - dev + pull_request: + branches: + - "*" + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: "14" + - run: yarn + - run: yarn db-gen + - run: yarn nx lint + - run: yarn nx test + - run: yarn nx build blueprints diff --git a/apps/blueprints/specs/index.spec.tsx b/apps/blueprints/specs/index.spec.tsx index 13f1131..533d232 100644 --- a/apps/blueprints/specs/index.spec.tsx +++ b/apps/blueprints/specs/index.spec.tsx @@ -1,10 +1,15 @@ import React from "react"; import { render } from "@testing-library/react"; - import Index from "../src/pages/index"; +import * as nextRouter from "next/router"; + +const useRouter = jest.spyOn(nextRouter, "useRouter"); describe("Index", () => { it("should render successfully", () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + useRouter.mockImplementationOnce(() => ({ query: {} } as any)); + const { baseElement } = render( ); diff --git a/apps/blueprints/src/components/BBCode.tsx b/apps/blueprints/src/components/BBCode.tsx index 2c05966..f737944 100644 --- a/apps/blueprints/src/components/BBCode.tsx +++ b/apps/blueprints/src/components/BBCode.tsx @@ -4,7 +4,7 @@ import { FactorioIcon } from "./FactorioIcon"; class ImgTag extends Tag { toReact() { const content = this.getContent(true); - const img = (this.params as any).img; + const img = (this.params as Record).img; const [type, item] = img.split("/"); if (type === "item") { return ( @@ -21,7 +21,7 @@ class ImgTag extends Tag { class ItemTag extends Tag { toReact() { const content = this.getContent(true); - const item = (this.params as any).item; + const item = (this.params as Record).item; if (item) { return ( <> @@ -36,7 +36,7 @@ class ItemTag extends Tag { class VirtualSignalTag extends Tag { toReact() { - const signal = (this.params as any)["virtual-signal"]; + const signal = (this.params as Record)["virtual-signal"]; const content = this.getContent(true); if (signal) { return ( @@ -50,9 +50,9 @@ class VirtualSignalTag extends Tag { } } -parser.registerTag("img", ImgTag as any); -parser.registerTag("item", ItemTag as any); -parser.registerTag("virtual-signal", VirtualSignalTag as any); +parser.registerTag("img", ImgTag as typeof Tag); +parser.registerTag("item", ItemTag as typeof Tag); +parser.registerTag("virtual-signal", VirtualSignalTag as typeof Tag); export const BBCode: React.FC<{ code: string }> = ({ code }) => { return <>{parser.toReact(code)}; diff --git a/apps/blueprints/src/components/FullscreenImage.tsx b/apps/blueprints/src/components/FullscreenImage.tsx index 9e0797a..4deee4d 100644 --- a/apps/blueprints/src/components/FullscreenImage.tsx +++ b/apps/blueprints/src/components/FullscreenImage.tsx @@ -34,11 +34,13 @@ export const FullscreenImage: React.FC = ({ alt, src, clos
{ + // eslint-disable-next-line @typescript-eslint/no-explicit-any if ((e as any).target.nodeName.toUpperCase() !== "IMG") { close(); } }} onTouchEnd={(e) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any if ((e as any).target.nodeName.toUpperCase() !== "IMG") { close(); } diff --git a/apps/blueprints/src/hooks/fetch.ts b/apps/blueprints/src/hooks/fetch.ts index c811bc2..8a26224 100644 --- a/apps/blueprints/src/hooks/fetch.ts +++ b/apps/blueprints/src/hooks/fetch.ts @@ -1,6 +1,7 @@ import { useEffect, useState } from "react"; import { createState, useState as useGlobalState } from "@hookstate/core"; +// eslint-disable-next-line @typescript-eslint/no-explicit-any const recordMapState = createState>({}); export const useFetch = ( @@ -31,6 +32,7 @@ export const useFetch = ( }; fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [url, skip]); return { loading, data: data ?? null, error }; diff --git a/apps/blueprints/src/pages/blueprint/[blueprintId].tsx b/apps/blueprints/src/pages/blueprint/[blueprintId].tsx index ad7b3e2..e9a381f 100644 --- a/apps/blueprints/src/pages/blueprint/[blueprintId].tsx +++ b/apps/blueprints/src/pages/blueprint/[blueprintId].tsx @@ -220,7 +220,7 @@ export const Index: NextPage = ({ {selected.data.blueprint_hash && typeof window !== "undefined" && ( )} diff --git a/apps/blueprints/src/pages/index.tsx b/apps/blueprints/src/pages/index.tsx index 6e97917..b62061c 100644 --- a/apps/blueprints/src/pages/index.tsx +++ b/apps/blueprints/src/pages/index.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useState } from "react"; import { NextPage, NextPageContext } from "next"; -import Link from "next/link"; import { useRouter } from "next/router"; import { searchBlueprintPages, init } from "@factorio-sites/database"; import { BlueprintPage } from "@factorio-sites/types"; @@ -13,8 +12,6 @@ import { queryValueAsArray } from "../utils/query.utils"; import { useFbeData } from "../hooks/fbe.hook"; import { Box, - Heading, - Flex, Text, Input, InputGroup, diff --git a/apps/blueprints/src/pages/login.tsx b/apps/blueprints/src/pages/login.tsx index 29baf0b..4c4bc3f 100644 --- a/apps/blueprints/src/pages/login.tsx +++ b/apps/blueprints/src/pages/login.tsx @@ -11,7 +11,7 @@ import { Box, Text, } from "@chakra-ui/react"; -import { Formik, Field } from "formik"; +import { Formik, Field, FieldProps } from "formik"; import { Panel } from "../components/Panel"; import { css } from "@emotion/react"; import { validateLoginForm } from "../utils/validate"; @@ -56,11 +56,11 @@ export const Login: NextPage = () => { {({ isSubmitting, handleSubmit, status }) => (
- {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Email address @@ -71,11 +71,11 @@ export const Login: NextPage = () => { - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Password diff --git a/apps/blueprints/src/pages/register.tsx b/apps/blueprints/src/pages/register.tsx index f955f83..7aa60c7 100644 --- a/apps/blueprints/src/pages/register.tsx +++ b/apps/blueprints/src/pages/register.tsx @@ -11,7 +11,7 @@ import { Text, Box, } from "@chakra-ui/react"; -import { Formik, Field } from "formik"; +import { Formik, Field, FieldProps } from "formik"; import { Panel } from "../components/Panel"; import { css } from "@emotion/react"; import { validateRegisterForm } from "../utils/validate"; @@ -52,11 +52,11 @@ export const Register: NextPage = () => { {({ isSubmitting, handleSubmit, errors }) => ( - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Email address @@ -68,11 +68,11 @@ export const Register: NextPage = () => { - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Username @@ -83,11 +83,11 @@ export const Register: NextPage = () => { - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Password @@ -98,11 +98,11 @@ export const Register: NextPage = () => { - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Repeat Password diff --git a/apps/blueprints/src/pages/user/blueprint-create.tsx b/apps/blueprints/src/pages/user/blueprint-create.tsx index 9d845e7..61b3882 100644 --- a/apps/blueprints/src/pages/user/blueprint-create.tsx +++ b/apps/blueprints/src/pages/user/blueprint-create.tsx @@ -12,7 +12,7 @@ import { Text, Textarea, } from "@chakra-ui/react"; -import { Formik, Field } from "formik"; +import { Formik, Field, FieldProps } from "formik"; import { css } from "@emotion/react"; import { chakraResponsive } from "@factorio-sites/web-utils"; import { Panel } from "../../components/Panel"; @@ -62,11 +62,11 @@ export const UserBlueprintCreate: NextPage = () => { - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Title @@ -77,11 +77,11 @@ export const UserBlueprintCreate: NextPage = () => { - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Description @@ -92,8 +92,12 @@ export const UserBlueprintCreate: NextPage = () => { - {({ field, meta }: any) => ( - + {({ field, meta }: FieldProps) => ( + Tags (WIP) = ({ blueprintPage, sel - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Blueprint string diff --git a/apps/blueprints/src/pages/user/edit.tsx b/apps/blueprints/src/pages/user/edit.tsx index ac6222e..896a00e 100644 --- a/apps/blueprints/src/pages/user/edit.tsx +++ b/apps/blueprints/src/pages/user/edit.tsx @@ -9,7 +9,7 @@ import { SimpleGrid, Button, } from "@chakra-ui/react"; -import { Formik, Field } from "formik"; +import { Formik, Field, FieldProps } from "formik"; import { css } from "@emotion/react"; import { Panel } from "../../components/Panel"; import { validateUserForm } from "../../utils/validate"; @@ -50,11 +50,11 @@ export const UserEdit: NextPage = () => { {({ isSubmitting, handleSubmit }) => ( - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Email address @@ -65,11 +65,11 @@ export const UserEdit: NextPage = () => { - {({ field, meta }: any) => ( + {({ field, meta }: FieldProps) => ( Username diff --git a/apps/blueprints/src/utils/api-handler.ts b/apps/blueprints/src/utils/api-handler.ts index 1fa03b4..28416ae 100644 --- a/apps/blueprints/src/utils/api-handler.ts +++ b/apps/blueprints/src/utils/api-handler.ts @@ -27,10 +27,11 @@ export class ApiError extends Error { } export const apiHandler = ( - fn: (req: NextApiRequest, res: NextApiResponse, ctx: CustomContext) => Promise + fn: (req: NextApiRequest, res: NextApiResponse, ctx: CustomContext) => Promise ) => async (req: NextApiRequest, res: NextApiResponse) => { await init(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any const ip_header = (req.headers["x-forwarded-for"] || (req as any).ip) as string; const ip = ip_header ? ip_header.split(",")[0] : ""; const useragent = req.headers["user-agent"] as string; diff --git a/apps/blueprints/src/utils/api.utils.ts b/apps/blueprints/src/utils/api.utils.ts index 742fb37..82924d7 100644 --- a/apps/blueprints/src/utils/api.utils.ts +++ b/apps/blueprints/src/utils/api.utils.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any export const parseDatabaseError = (reason: any): Record | null => { const errors: Record = {}; console.log(reason); diff --git a/apps/blueprints/src/utils/openid_steam.ts b/apps/blueprints/src/utils/openid_steam.ts index a1e3d05..3f43353 100644 --- a/apps/blueprints/src/utils/openid_steam.ts +++ b/apps/blueprints/src/utils/openid_steam.ts @@ -20,7 +20,7 @@ export const getSteamRedirectUrl = async (realm_url: string): Promise => export const fetchSteamProfile = async (steam_id: string, api_key: string) => { try { - const response = await phin<{ response: { players: any } }>({ + const response = await phin<{ response: { players?: Record[] } }>({ url: `https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=${api_key}&steamids=${steam_id}`, parse: "json", }); diff --git a/apps/blueprints/src/utils/page-handler.ts b/apps/blueprints/src/utils/page-handler.ts index 1ac0d84..bcedd03 100644 --- a/apps/blueprints/src/utils/page-handler.ts +++ b/apps/blueprints/src/utils/page-handler.ts @@ -3,6 +3,7 @@ import { getSessionByToken, init } from "@factorio-sites/database"; import { getSessionToken } from "@factorio-sites/node-utils"; interface GetServerSidePropsReturn { + // eslint-disable-next-line @typescript-eslint/no-explicit-any props: Record; } diff --git a/libs/database/src/lib/gcp-storage.ts b/libs/database/src/lib/gcp-storage.ts index f6ac48b..b287174 100644 --- a/libs/database/src/lib/gcp-storage.ts +++ b/libs/database/src/lib/gcp-storage.ts @@ -1,22 +1,24 @@ import { Storage } from "@google-cloud/storage"; -import { getEnvOrThrow } from "./env.util"; +import { getEnv } from "./env.util"; const storage = new Storage(); -const BLUEPRINT_BUCKET = storage.bucket(getEnvOrThrow("GCP_BLUEPRINT_STRINGS_BUCKET")); -const IMAGE_BUCKET = storage.bucket(getEnvOrThrow("GCP_BLUEPRINT_IMAGES_BUCKET")); +const BLUEPRINT_BUCKET = getEnv("GCP_BLUEPRINT_STRINGS_BUCKET"); +const IMAGE_BUCKET = getEnv("GCP_BLUEPRINT_IMAGES_BUCKET"); /* * BlueprintString */ export async function getBlueprintStringByHash(hash: string): Promise { - const [buffer] = await BLUEPRINT_BUCKET.file(hash).download(); + if (!BLUEPRINT_BUCKET) throw Error("Missing GCP_BLUEPRINT_STRINGS_BUCKET env variable"); + const [buffer] = await storage.bucket(BLUEPRINT_BUCKET).file(hash).download(); return buffer ? buffer.toString() : null; } export async function saveBlueprintString(hash: string, content: string) { - await BLUEPRINT_BUCKET.file(hash).save(content); + if (!BLUEPRINT_BUCKET) throw Error("Missing GCP_BLUEPRINT_STRINGS_BUCKET env variable"); + await storage.bucket(BLUEPRINT_BUCKET).file(hash).save(content); } /* @@ -30,7 +32,8 @@ export async function saveBlueprintImage( image: Buffer, type: sizeType = "original" ): Promise { - return IMAGE_BUCKET.file(`${type}/${hash}.webp`).save(image, { + if (!IMAGE_BUCKET) throw Error("Missing GCP_BLUEPRINT_IMAGES_BUCKET env variable"); + return storage.bucket(IMAGE_BUCKET).file(`${type}/${hash}.webp`).save(image, { contentType: "image/webp", }); } @@ -39,7 +42,8 @@ export async function hasBlueprintImage( hash: string, type: sizeType = "original" ): Promise { - const [result] = await IMAGE_BUCKET.file(`${type}/${hash}.webp`).exists(); + if (!IMAGE_BUCKET) throw Error("Missing GCP_BLUEPRINT_IMAGES_BUCKET env variable"); + const [result] = await storage.bucket(IMAGE_BUCKET).file(`${type}/${hash}.webp`).exists(); return result; } @@ -47,6 +51,7 @@ export async function getBlueprintByImageHash( hash: string, type: sizeType = "original" ): Promise { - const [result] = await IMAGE_BUCKET.file(`${type}/${hash}.webp`).download(); + if (!IMAGE_BUCKET) throw Error("Missing GCP_BLUEPRINT_IMAGES_BUCKET env variable"); + const [result] = await storage.bucket(IMAGE_BUCKET).file(`${type}/${hash}.webp`).download(); return result; } diff --git a/libs/database/src/lib/postgres/database.ts b/libs/database/src/lib/postgres/database.ts index 5091fac..903b818 100644 --- a/libs/database/src/lib/postgres/database.ts +++ b/libs/database/src/lib/postgres/database.ts @@ -39,6 +39,7 @@ const promise = _init() return result; }) .catch((reason) => { + if (process.env.JEST_WORKER_ID) return; console.log("Database failed to init!", reason); });