From f5ff616491bce1a3463428366923fcf0a6ac7df9 Mon Sep 17 00:00:00 2001 From: catensia Date: Thu, 1 Dec 2022 21:29:04 +0900 Subject: [PATCH 1/7] feat: Initial release --- .dockerignore | 5 +++++ Dockerfile.prod | 15 +++++++++++++++ docker-compose.yml | 27 +++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile.prod create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0b7d2c7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +Dockerfile +.git +.gitignore +.dockerignore \ No newline at end of file diff --git a/Dockerfile.prod b/Dockerfile.prod new file mode 100644 index 0000000..bf14beb --- /dev/null +++ b/Dockerfile.prod @@ -0,0 +1,15 @@ +FROM node:latest + +WORKDIR /usr/src/app + +COPY . ./ + +WORKDIR /usr/src/app/client +RUN npm install +RUN npm run build + +WORKDIR /usr/src/app/server +RUN npm install +RUN npm run build + +EXPOSE 4000 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d94f6d3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,27 @@ +version: "3.8" + +services: + prod: + build: + context: . + dockerfile: Dockerfile.prod + container_name: prod + ports: + - "4000:4000" + command: npm run start + networks: + - webnet + depends_on: + - redis + + redis: + container_name: redis + image: redis:5 + command: redis-server + networks: + - webnet + ports: + - "6379:6379" + +networks: + webnet: From 4bdcbb1dbd891296ed2e4c999e7e364ecb82a12c Mon Sep 17 00:00:00 2001 From: catensia Date: Thu, 1 Dec 2022 22:18:07 +0900 Subject: [PATCH 2/7] feat: Rename container and add workflow for CD --- .github/workflows/release-autopull.yml | 21 +++++++++++++++++++++ docker-compose.yml | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/release-autopull.yml diff --git a/.github/workflows/release-autopull.yml b/.github/workflows/release-autopull.yml new file mode 100644 index 0000000..c11255b --- /dev/null +++ b/.github/workflows/release-autopull.yml @@ -0,0 +1,21 @@ +name: release-autopull +on: + push: + branches: release + +jobs: + distribute: + name: distribute + runs-on: ubuntu-latest + steps: + - name: git pull and restart docker + uses: appleboy/ssh-action@master + with: + host: ${{secrets.REMOTE_IP}} + username: ${{secrets.REMOTE_SSH_ID}} + password: ${{secrets.REMOTE_PASSWORD}} + port: ${{secrets.REMOTE_SSH_PORT}} + script: | + cd /root/runwithme + git pull https://${{secrets.PAT}}@github.com/boostcampwm-2022/WEB26-RunWithMe.git release + docker-compose restart runwithme \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index d94f6d3..a8a7457 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,11 @@ version: "3.8" services: - prod: + runwithme: build: context: . dockerfile: Dockerfile.prod - container_name: prod + container_name: runwithme ports: - "4000:4000" command: npm run start From 806b1f466bd37f7be791dfd1779cca4710cde31b Mon Sep 17 00:00:00 2001 From: pushedrumex Date: Thu, 1 Dec 2022 21:42:43 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=EB=AA=A8=EC=A7=91/=EC=BD=94?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80=20=EB=B2=84=ED=8A=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 13 +++++++------ client/src/hooks/http/useHttpGet.ts | 16 ++++++++++------ client/src/hooks/http/useHttpPatch.ts | 7 +++---- client/src/hooks/http/useHttpPost.ts | 9 ++++++--- client/src/pages/Courses/Courses.tsx | 5 ++--- client/src/pages/NewCourse/NewCourse.tsx | 12 +++--------- client/src/pages/RecruitDetail/RecruitDetail.tsx | 9 ++++++--- client/src/pages/Recruits/Recruits.tsx | 2 ++ client/src/utils/validationUtils.ts | 4 ++-- server/src/recruit/recruit.controller.ts | 9 +++++---- 10 files changed, 46 insertions(+), 40 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8632539..55ac284 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,8 @@ { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": true - }, -} \ No newline at end of file + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "cSpell.words": ["typeorm"] +} diff --git a/client/src/hooks/http/useHttpGet.ts b/client/src/hooks/http/useHttpGet.ts index eb5b7a4..41e2cc2 100644 --- a/client/src/hooks/http/useHttpGet.ts +++ b/client/src/hooks/http/useHttpGet.ts @@ -2,14 +2,18 @@ import useAxios from "./useAxios"; const useHttpGet = () => { const { axios } = useAxios(); - const get = (url: string, query?: { [key: string]: any }): Promise => { - return axios - .get(url, { + const get = async (url: string, query?: { [key: string]: any }): Promise => { + try { + const res = await axios.get(url, { params: query, - }) - .then((res) => { - return res.data; }); + if (res.data.statusCode >= 400) { + throw new Error(res.data.message); + } + return res.data; + } catch (error) { + throw error; + } }; return { get }; }; diff --git a/client/src/hooks/http/useHttpPatch.ts b/client/src/hooks/http/useHttpPatch.ts index f583f7e..aafe8f4 100644 --- a/client/src/hooks/http/useHttpPatch.ts +++ b/client/src/hooks/http/useHttpPatch.ts @@ -2,10 +2,9 @@ import useAxios from "./useAxios"; const useHttpPatch = () => { const { axios } = useAxios(); - const patch = (url: string, data: { [key: string]: any }) => { - return axios.patch(url, data).then((res) => { - return res.data; - }); + const patch = async (url: string, data: { [key: string]: any }) => { + const res = await axios.patch(url, data); + return res.data; }; return { patch }; }; diff --git a/client/src/hooks/http/useHttpPost.ts b/client/src/hooks/http/useHttpPost.ts index 4122a5c..988feeb 100644 --- a/client/src/hooks/http/useHttpPost.ts +++ b/client/src/hooks/http/useHttpPost.ts @@ -3,11 +3,14 @@ import useAxios from "./useAxios"; const useHttpPost = () => { const { axios } = useAxios(); - const post = (url: string, data: Req): Promise> => { - return axios + const post = async (url: string, data: Req): Promise> => { + return await axios .post(url, data) .then((res) => { - return res.data; + if (res.data.statusCode >= 400) { + throw new Error(res.data.message); + } + if (res) return res.data; }) .catch((error) => { throw error; diff --git a/client/src/pages/Courses/Courses.tsx b/client/src/pages/Courses/Courses.tsx index 428c619..f583c0d 100644 --- a/client/src/pages/Courses/Courses.tsx +++ b/client/src/pages/Courses/Courses.tsx @@ -13,6 +13,7 @@ import useGet from "#hooks/http/useHttpGet"; import { LOCATION_ICON } from "#assets/icons"; import CourseCard from "#components/Card/CourseCard/CourseCard"; import { Course } from "#types/Course"; +import PlusButton from "#components/PlusButton/PlusButton"; const CourseList = styled.div` padding: 2rem; @@ -66,9 +67,6 @@ const Courses = () => { sendCourseFetchRequest(); }, []); - useEffect(() => { - console.log(cardList.length); - }, [cardList]); return ( <>
@@ -119,6 +117,7 @@ const Courses = () => { ))} + ); }; diff --git a/client/src/pages/NewCourse/NewCourse.tsx b/client/src/pages/NewCourse/NewCourse.tsx index 4eab07a..7ffa491 100644 --- a/client/src/pages/NewCourse/NewCourse.tsx +++ b/client/src/pages/NewCourse/NewCourse.tsx @@ -16,10 +16,8 @@ import useAuth from "#hooks/useAuth"; import ConfirmModal from "#components/ConfirmModal/ConfirmModal"; import { LOCAL_API_PATH } from "#types/LocalAPIType"; //#endregion -const img = - "https://kr.object.ncloudstorage.com/j199/img/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202022-11-20%20%EC%98%A4%ED%9B%84%204.01.56.png"; + const NewCourse = () => { - const { userIdx: userId } = useAuth(); const [title, onChangeTitle] = useInput(courseTitleValidator); const query = useLocalAPI(LOCAL_API_PATH.REGION_CODE); const { post } = useHttpPost(); @@ -47,22 +45,18 @@ const NewCourse = () => { const { lng: x, lat: y } = getLatLngByXY(path[0]); const regions = await query({ x, y }); // [0]: BCode, [1]: HCode - const { code: hCode, region_3depth_name: name } = regions.documents[1]; - console.log(title); + const { code: hCode } = regions.documents[1]; const response: any = await post("/course", { title, path: path.map(getLatLngByXY), - img, pathLength, - userId, hCode, - name, }); navigate(`/course/${response.data.courseId}`); } catch (error: any) { alert(error.message); } - }, [path]); + }, [path, title, pathLength]); return (
diff --git a/client/src/pages/RecruitDetail/RecruitDetail.tsx b/client/src/pages/RecruitDetail/RecruitDetail.tsx index aa0e79a..2fcc0b5 100644 --- a/client/src/pages/RecruitDetail/RecruitDetail.tsx +++ b/client/src/pages/RecruitDetail/RecruitDetail.tsx @@ -1,4 +1,4 @@ -import { useParams } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; import useHttpPost from "#hooks/http/useHttpPost"; import { useCallback, useState } from "react"; import useShowMap from "#hooks/useShowMap"; @@ -13,7 +13,6 @@ import ConfirmModal from "#components/ConfirmModal/ConfirmModal"; const RecruitDetail = () => { const { id } = useParams(); - const { data: recruit, isLoading } = useRecruitDetailQuery(Number(id)); const { post } = useHttpPost(); @@ -34,7 +33,11 @@ const RecruitDetail = () => { const onSubmitJoin = useCallback(async () => { try { await post("/recruit/join", { recruitId: String(id) }); - } catch {} + } catch (error: any) { + alert(error.message); + } finally { + window.location.reload(); + } }, []); if (isLoading) return
Loading...
; diff --git a/client/src/pages/Recruits/Recruits.tsx b/client/src/pages/Recruits/Recruits.tsx index 3e2d1e5..f433566 100644 --- a/client/src/pages/Recruits/Recruits.tsx +++ b/client/src/pages/Recruits/Recruits.tsx @@ -13,6 +13,7 @@ import useGet from "#hooks/http/useHttpGet"; import { LOCATION_ICON, CLOCK_ICON } from "#assets/icons"; import RecruitCard from "#components/Card/RecruitCard/RecruitCard"; import { Recruit } from "#types/Recruit"; +import PlusButton from "#components/PlusButton/PlusButton"; const RecruitList = styled.div` padding: 2rem; @@ -140,6 +141,7 @@ const Recruits = () => { ))} + ); }; diff --git a/client/src/utils/validationUtils.ts b/client/src/utils/validationUtils.ts index 58dc2d8..8d014fd 100644 --- a/client/src/utils/validationUtils.ts +++ b/client/src/utils/validationUtils.ts @@ -18,9 +18,9 @@ export const hNameValidator = (hCode: string) => { }; export const courseTitleValidator = (title: string) => { - return !title.trim() ? "제목을 입력하세요" : ""; + return title.trim() ? "" : "제목을 입력하세요"; }; export const recruitTitleValidator = (title: string) => { - return !title.trim() ? "제목을 입력하세요" : ""; + return title.trim() ? "" : "제목을 입력하세요"; }; diff --git a/server/src/recruit/recruit.controller.ts b/server/src/recruit/recruit.controller.ts index 8bc2172..01131aa 100644 --- a/server/src/recruit/recruit.controller.ts +++ b/server/src/recruit/recruit.controller.ts @@ -37,17 +37,18 @@ export class RecruitController { const userId = joinRecruitDto.getUserId(); if (!(await this.recruitService.isExistingRecruit(recruitId))) { - ResponseEntity.NOT_FOUND("존재하지 않는 게시글입니다"); + return ResponseEntity.NOT_FOUND("존재하지 않는 게시글입니다"); } if (await this.recruitService.isAuthorOfRecruit(recruitId, userId)) { - ResponseEntity.LOCKED("자신의 게시글에 참가할 수 없습니다"); + console.log("!23123123123"); + return ResponseEntity.LOCKED("자신의 게시글에 참가할 수 없습니다"); } if (await this.recruitService.isParticipating(recruitId, userId)) { - ResponseEntity.LOCKED("이미 참여중인 게시글입니다"); + return ResponseEntity.LOCKED("이미 참여중인 게시글입니다"); } if (!(await this.recruitService.isVacancy(recruitId))) { - ResponseEntity.LOCKED("모집 상한에 도달했습니다"); + return ResponseEntity.LOCKED("모집 상한에 도달했습니다"); } this.recruitService.join(joinRecruitDto); return ResponseEntity.CREATED(); From 0bdec87e622ce44ef0c2d0c13bbf19c72a356ddc Mon Sep 17 00:00:00 2001 From: pushedrumex Date: Thu, 1 Dec 2022 21:47:04 +0900 Subject: [PATCH 4/7] =?UTF-8?q?console.log=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/auth/auth.controller.ts | 1 - server/src/course/dto/response/get-many.response.ts | 2 -- server/src/recruit/recruit.controller.ts | 1 - 3 files changed, 4 deletions(-) diff --git a/server/src/auth/auth.controller.ts b/server/src/auth/auth.controller.ts index a9c0a76..0b47039 100644 --- a/server/src/auth/auth.controller.ts +++ b/server/src/auth/auth.controller.ts @@ -58,7 +58,6 @@ export class AuthController { @ApiOkResponse({ description: "로그인 성공" }) @Post("/login") async validateUser(@Body() loginUserDto: LoginUserReqDto, @Res() res: Response) { - console.log(loginUserDto); const data = await this.authService.validateUser(loginUserDto); res.cookie("refreshToken", data.refreshToken, { httpOnly: true, diff --git a/server/src/course/dto/response/get-many.response.ts b/server/src/course/dto/response/get-many.response.ts index 1b47de5..8da8efa 100644 --- a/server/src/course/dto/response/get-many.response.ts +++ b/server/src/course/dto/response/get-many.response.ts @@ -7,9 +7,7 @@ export class GetManyResponseDto { course: CourseResponseDto; static fromEntity(course: any): GetManyResponseDto { - console.log(course); const data = instanceToPlain(course); - console.log(data); return plainToInstance(GetManyResponseDto, data, { excludeExtraneousValues: true }); // return plainToInstance(GetManyResponseDto, course); } diff --git a/server/src/recruit/recruit.controller.ts b/server/src/recruit/recruit.controller.ts index 01131aa..5aad3a5 100644 --- a/server/src/recruit/recruit.controller.ts +++ b/server/src/recruit/recruit.controller.ts @@ -40,7 +40,6 @@ export class RecruitController { return ResponseEntity.NOT_FOUND("존재하지 않는 게시글입니다"); } if (await this.recruitService.isAuthorOfRecruit(recruitId, userId)) { - console.log("!23123123123"); return ResponseEntity.LOCKED("자신의 게시글에 참가할 수 없습니다"); } From 42efd1f48e703e2787d619993931cb4cc5f6b13d Mon Sep 17 00:00:00 2001 From: pushedrumex Date: Thu, 1 Dec 2022 21:52:42 +0900 Subject: [PATCH 5/7] resolve eslint problem --- client/src/pages/NewCourse/NewCourse.tsx | 1 - client/src/pages/RecruitDetail/RecruitDetail.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/pages/NewCourse/NewCourse.tsx b/client/src/pages/NewCourse/NewCourse.tsx index 7ffa491..9f708ed 100644 --- a/client/src/pages/NewCourse/NewCourse.tsx +++ b/client/src/pages/NewCourse/NewCourse.tsx @@ -12,7 +12,6 @@ import { useNavigate } from "react-router-dom"; import { courseTitleValidator } from "#utils/validationUtils"; import { RegionResponse } from "#types/Region"; import { CourseForm } from "./NewCourse.styles"; -import useAuth from "#hooks/useAuth"; import ConfirmModal from "#components/ConfirmModal/ConfirmModal"; import { LOCAL_API_PATH } from "#types/LocalAPIType"; //#endregion diff --git a/client/src/pages/RecruitDetail/RecruitDetail.tsx b/client/src/pages/RecruitDetail/RecruitDetail.tsx index 2fcc0b5..62d69a0 100644 --- a/client/src/pages/RecruitDetail/RecruitDetail.tsx +++ b/client/src/pages/RecruitDetail/RecruitDetail.tsx @@ -1,4 +1,4 @@ -import { useNavigate, useParams } from "react-router-dom"; +import { useParams } from "react-router-dom"; import useHttpPost from "#hooks/http/useHttpPost"; import { useCallback, useState } from "react"; import useShowMap from "#hooks/useShowMap"; From e2a8c7f693491752b2d155c1f7244eb7236aa0a5 Mon Sep 17 00:00:00 2001 From: catensia Date: Thu, 1 Dec 2022 22:27:32 +0900 Subject: [PATCH 6/7] feat: Update script and add release check workflow feat: Update CD workflow feat: Modify workflow file feat: Update workflow file --- .github/workflows/release-autopull.yml | 6 +- .github/workflows/release-check.yml | 79 ++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/release-check.yml diff --git a/.github/workflows/release-autopull.yml b/.github/workflows/release-autopull.yml index c11255b..815f86b 100644 --- a/.github/workflows/release-autopull.yml +++ b/.github/workflows/release-autopull.yml @@ -16,6 +16,6 @@ jobs: password: ${{secrets.REMOTE_PASSWORD}} port: ${{secrets.REMOTE_SSH_PORT}} script: | - cd /root/runwithme - git pull https://${{secrets.PAT}}@github.com/boostcampwm-2022/WEB26-RunWithMe.git release - docker-compose restart runwithme \ No newline at end of file + cd /root/runwithme + git pull https://github.com/boostcampwm-2022/WEB26-RunWithMe.git release + docker-compose down && docker-compose build --no-cache && docker-compose up \ No newline at end of file diff --git a/.github/workflows/release-check.yml b/.github/workflows/release-check.yml new file mode 100644 index 0000000..9f5a68d --- /dev/null +++ b/.github/workflows/release-check.yml @@ -0,0 +1,79 @@ +name: build + eslint check + +on: + pull_request: + branches: + - release + +jobs: + check: + name: check + runs-on: ubuntu-latest + outputs: + client: ${{steps.filter.outputs.client}} + server: ${{steps.filter.outputs.server}} + steps: + - uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + client: + - 'client/**' + server: + - 'server/**' + + client: + needs: check + if: ${{needs.check.outputs.client=='true'}} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Nodejs Setup + uses: actions/setup-node@v2 + + - name: Cache client node modules + id: cache-client + uses: actions/cache@v3 + with: + path: client/node_modules + key: npm-packages-client-${{hashFiles('**/package-lock.json')}} + + - name: Install client dependencies + if: ${{steps.cache-client.outputs.cache-hit != 'true'}} + run: cd client && npm install + + - name: Client eslint check + run: ./client/node_modules/.bin/eslint client/src --ext .ts,.tsx + + - name: Run client build check + run: cd client && npm run build + + server: + needs: check + if: ${{needs.check.outputs.server=='true'}} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Nodejs Setup + uses: actions/setup-node@v2 + + - name: Cache server node modules + id: cache-server + uses: actions/cache@v3 + with: + path: server/node_modules + key: npm-packages-server-${{hashFiles('**/package-lock.json')}} + + - name: Install server dependencies + if: ${{steps.cache-server.outputs.cache-hit != 'true'}} + run: cd server && npm install + + - name: server eslint check + run: ./server/node_modules/.bin/eslint server/src --ext .ts,.tsx + + - name: Run server build check + run: cd server && npm run build From 419cfb51eb9beb579925940758c76713c8c5b89c Mon Sep 17 00:00:00 2001 From: catensia Date: Thu, 1 Dec 2022 23:17:37 +0900 Subject: [PATCH 7/7] feat: Update workflow --- .github/workflows/release-autopull.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-autopull.yml b/.github/workflows/release-autopull.yml index 815f86b..55c6e51 100644 --- a/.github/workflows/release-autopull.yml +++ b/.github/workflows/release-autopull.yml @@ -18,4 +18,4 @@ jobs: script: | cd /root/runwithme git pull https://github.com/boostcampwm-2022/WEB26-RunWithMe.git release - docker-compose down && docker-compose build --no-cache && docker-compose up \ No newline at end of file + docker-compose down && docker-compose build --no-cache && docker-compose up -d \ No newline at end of file