diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..e5f6d9f4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*] +end_of_line = lf + +[*.{bat,cmd}] +end_of_line = crlf diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..f6a525db --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto eol=lf +*.bat text eol=crlf +*.cmd text eol=crlf diff --git a/.githooks/commit-msg b/.githooks/commit-msg index 1b702ffa..d0092b2d 100755 --- a/.githooks/commit-msg +++ b/.githooks/commit-msg @@ -9,37 +9,4 @@ if grep -qE '^\[[A-Za-z]+\]' "$MSG_FILE"; then exit 1 fi -# Allow merge/revert/fixup/squash commits without JIRA key -if grep -qE '^(Merge|Revert|fixup!|squash!)' "$MSG_FILE"; then - exit 0 -fi - -if ! grep -qiE '(^|[^A-Z0-9])PB-[0-9]+([^A-Z0-9]|$)' "$MSG_FILE"; then - BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "") - # 브랜치명에 `pb-81`처럼 소문자로 들어온 케이스도 허용한다. - JIRA=$(echo "$BRANCH" | grep -oiE 'pb-[0-9]+' | head -n1 | tr '[:lower:]' '[:upper:]') - if [ -n "$JIRA" ]; then - TMP_FILE=$(mktemp) - FIRST_LINE=$(head -n 1 "$MSG_FILE") - REST_LINES=$(tail -n +2 "$MSG_FILE") - { - TYPE=$(echo "$FIRST_LINE" | sed -nE 's/^([a-zA-Z]+):.*/\1/p') - SUBJECT=$(echo "$FIRST_LINE" | sed -E 's/^[a-zA-Z]+:[[:space:]]*//') - if [ -n "$TYPE" ]; then - printf "%s: %s %s\n" "$TYPE" "$JIRA" "$SUBJECT" - else - printf "%s %s\n" "$JIRA" "$FIRST_LINE" - fi - printf "%s\n" "$REST_LINES" - } > "$TMP_FILE" - mv "$TMP_FILE" "$MSG_FILE" - exit 0 - fi -fi - -if grep -qiE '(^|[^A-Z0-9])PB-[0-9]+([^A-Z0-9]|$)' "$MSG_FILE"; then - exit 0 -fi - -echo "JIRA key (e.g., PB-123) is required in commit messages." -exit 1 +exit 0 diff --git a/.githooks/prepare-commit-msg b/.githooks/prepare-commit-msg deleted file mode 100755 index 81f23f2f..00000000 --- a/.githooks/prepare-commit-msg +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -set -e - -MSG_FILE="$1" -SOURCE="$2" - -# Skip for merges or squash commits -case "$SOURCE" in - merge|squash) - exit 0 - ;; -esac - -BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "") -# 브랜치명에 `pb-81`처럼 소문자로 들어온 케이스도 허용한다. -JIRA=$(echo "$BRANCH" | grep -oiE 'pb-[0-9]+' | head -n1 | tr '[:lower:]' '[:upper:]') - -if [ -n "$JIRA" ] && ! grep -qE "(^|[^A-Z0-9])$JIRA([^A-Z0-9]|$)" "$MSG_FILE"; then - TMP_FILE=$(mktemp) - FIRST_LINE=$(head -n 1 "$MSG_FILE") - REST_LINES=$(tail -n +2 "$MSG_FILE") - TYPE=$(echo "$FIRST_LINE" | sed -nE 's/^([a-zA-Z]+):.*/\1/p') - SUBJECT=$(echo "$FIRST_LINE" | sed -E 's/^[a-zA-Z]+:[[:space:]]*//') - if [ -n "$TYPE" ]; then - printf "%s: %s %s\n" "$TYPE" "$JIRA" "$SUBJECT" > "$TMP_FILE" - else - printf "%s %s\n" "$JIRA" "$FIRST_LINE" > "$TMP_FILE" - fi - printf "%s\n" "$REST_LINES" >> "$TMP_FILE" - mv "$TMP_FILE" "$MSG_FILE" -fi diff --git a/.githooks/prepare-commit-msg.cmd b/.githooks/prepare-commit-msg.cmd deleted file mode 100644 index d6ca2613..00000000 --- a/.githooks/prepare-commit-msg.cmd +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -setlocal -set "HOOK=%~dp0prepare-commit-msg" -if exist "%ProgramFiles%\Git\bin\bash.exe" ( - "%ProgramFiles%\Git\bin\bash.exe" "%HOOK%" %* -) else ( - bash "%HOOK%" %* -) -exit /b %ERRORLEVEL% diff --git a/.github/PULL_REQUEST_TEMPLATE/bugfix.md b/.github/PULL_REQUEST_TEMPLATE/bugfix.md index ce5eb514..2ca9fc62 100644 --- a/.github/PULL_REQUEST_TEMPLATE/bugfix.md +++ b/.github/PULL_REQUEST_TEMPLATE/bugfix.md @@ -1,16 +1,7 @@ # 🐛 Bugfix PR -## 🔗 Jira Issue (필수) -- Key: **PB-** -- Link: https://parkjaehong.atlassian.net/browse/PB- - -> PR 제목: `PB-123 <짧은 요약>` -> 브랜치: `PB-123/` - ---- - -### 🔒 Close Issue (필수) -- GitHub: Closes # +## 🔗 GitHub Issue (필수) +- Closes # --- diff --git a/.github/PULL_REQUEST_TEMPLATE/chore.md b/.github/PULL_REQUEST_TEMPLATE/chore.md index cbab530c..717e1727 100644 --- a/.github/PULL_REQUEST_TEMPLATE/chore.md +++ b/.github/PULL_REQUEST_TEMPLATE/chore.md @@ -1,16 +1,7 @@ # 🧰 Chore PR -## 🔗 Jira Issue (필수) -- Key: **PB-** -- Link: https://parkjaehong.atlassian.net/browse/PB- - -> PR 제목: `PB-123 Chore: <짧은 요약>` -> 브랜치: `PB-123/chore-` - ---- - -### 🔒 Close Issue (필수) -- GitHub: Closes # +## 🔗 GitHub Issue (필수) +- Closes # --- diff --git a/.github/PULL_REQUEST_TEMPLATE/docs.md b/.github/PULL_REQUEST_TEMPLATE/docs.md index 65561438..9efa9b25 100644 --- a/.github/PULL_REQUEST_TEMPLATE/docs.md +++ b/.github/PULL_REQUEST_TEMPLATE/docs.md @@ -1,16 +1,7 @@ # 📝 Docs PR -## 🔗 Jira Issue (필수) -- Key: **PB-** -- Link: https://parkjaehong.atlassian.net/browse/PB- - -> PR 제목: `PB-123 Docs: <짧은 요약>` -> 브랜치: `PB-123/docs-` - ---- - -### 🔒 Close Issue (필수) -- GitHub: Closes # +## 🔗 GitHub Issue (필수) +- Closes # --- diff --git a/.github/PULL_REQUEST_TEMPLATE/feature.md b/.github/PULL_REQUEST_TEMPLATE/feature.md index d8978a37..48a6203c 100644 --- a/.github/PULL_REQUEST_TEMPLATE/feature.md +++ b/.github/PULL_REQUEST_TEMPLATE/feature.md @@ -1,11 +1,9 @@ # ✨ Feature PR ## 🔗 이슈 링크 (필수) -- Jira: https://parkjaehong.atlassian.net/browse/PB- - GitHub: Related # (필수) - GitHub: Closes # (Final PR만) -> PR 제목: `PB-123 <짧은 요약>` --- diff --git a/.github/PULL_REQUEST_TEMPLATE/refactor.md b/.github/PULL_REQUEST_TEMPLATE/refactor.md index 76299278..72d6f504 100644 --- a/.github/PULL_REQUEST_TEMPLATE/refactor.md +++ b/.github/PULL_REQUEST_TEMPLATE/refactor.md @@ -1,17 +1,7 @@ # 🧹 Refactor PR -## 🔗 Jira Issue (필수) -- Key: **PB-** -- Link: https://parkjaehong.atlassian.net/browse/PB- - -> PR 제목: `PB-123 <짧은 요약>` -> 브랜치: `PB-123/` - - ---- - -### 🔒 Close Issue (필수) -- GitHub: Closes # +## 🔗 GitHub Issue (필수) +- Closes # --- diff --git a/.github/PULL_REQUEST_TEMPLATE/test.md b/.github/PULL_REQUEST_TEMPLATE/test.md index 4e5cf9e8..9380b34c 100644 --- a/.github/PULL_REQUEST_TEMPLATE/test.md +++ b/.github/PULL_REQUEST_TEMPLATE/test.md @@ -1,11 +1,9 @@ # 🧪 Test PR ## 🔗 이슈 링크 (필수) -- Jira: https://parkjaehong.atlassian.net/browse/PB- - GitHub: Related # (필수) - GitHub: Closes # (Final PR만) -> PR 제목: `PB-123 Test: <짧은 요약>` --- diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 9fc4c600..f8942df1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,8 +17,8 @@ PR을 올리기 전에 다음 사항을 확인하세요: -- [ ] 브랜치명이 컨벤션을 따르는가? (`feature/`, `bugfix/`, `refactor/`) -- [ ] Jira 이슈 키가 제목에 포함되어 있는가? (예: `[Feat] TES-123: ...`) +- [ ] 브랜치명이 컨벤션을 따르는가? (`feature/`, `bugfix/`, `refactor/`, `chore/`, `docs/`, `test/`) +- [ ] 본문에 관련 GitHub 이슈가 연결되어 있는가? (예: `Closes #123`, `Related #123`) - [ ] 로컬에서 빌드 및 테스트가 통과하는가? - [ ] 코드 리뷰어를 지정했는가? - [ ] 관련 문서를 업데이트했는가? (필요 시) diff --git a/.github/workflows/jira-sync-put.yml b/.github/workflows/jira-sync-put.yml deleted file mode 100644 index c5cdb681..00000000 --- a/.github/workflows/jira-sync-put.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: Update Jira Issue on GitHub Edit - -on: - issues: - types: [edited] - -jobs: - update-jira: - runs-on: ubuntu-latest - # 제목에 'PB-'가 포함되어 있을 때만 실행 (무한 루프/오작동 방지) - if: contains(github.event.issue.title, 'PB-') - - steps: - - name: Extract Jira Key - id: get-key - run: | - TITLE="${{ github.event.issue.title }}" - # 정규식으로 [PB-123] 또는 PB-123 추출 - KEY=$(echo "$TITLE" | grep -o 'PB-[0-9]\+' | head -n 1) - echo "Jira Key Found: $KEY" - echo "key=$KEY" >> $GITHUB_OUTPUT - - - name: Update Jira Issue - uses: actions/github-script@v6 - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} - JIRA_KEY: ${{ steps.get-key.outputs.key }} - with: - script: | - const jiraKey = process.env.JIRA_KEY; - const baseUrl = process.env.JIRA_BASE_URL; - const email = process.env.JIRA_USER_EMAIL; - const token = process.env.JIRA_API_TOKEN; - - // 깃허브 이슈 정보 가져오기 - const ghTitle = context.payload.issue.title; - const ghBody = context.payload.issue.body || "내용 없음"; // 본문이 비었을 때 방어 - const ghUrl = context.payload.issue.html_url; - - - - // Jira API v3용 ADF(문서 포맷) 구조 만들기 - // 깃허브 마크다운을 억지로 변환하지 않고 '코드 블록'에 넣어 안전하게 전송합니다. - const adfBody = { - "type": "doc", - "version": 1, - "content": [ - { - // 경고문구 - "type": "paragraph", - "content": [ - { - "type": "text", - "text": "⚠️ GitHub에서 본문이 수정되었습니다. (원본 마크다운):" - } - ] - }, - { - // 코드블록 - "type": "codeBlock", - "attrs": { "language": "markdown" }, - "content": [ - { - "type": "text", - "text": ghBody - } - ] - }, - { - // 바로가기 링크 - "type": "paragraph", - "content": [ - { - "type": "text", - "text": "🔗 " - }, - { - "type": "text", - "text": "GitHub 이슈 바로가기", - "marks": [ - { - "type": "link", - "attrs": { - "href": ghUrl - } - } - ] - } - ] - } - ] - }; - - // Jira API 호출 (PUT) - const response = await fetch(`${baseUrl}/rest/api/3/issue/${jiraKey}`, { - method: 'PUT', - headers: { - 'Authorization': `Basic ${Buffer.from(`${email}:${token}`).toString('base64')}`, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - fields: { - summary: ghTitle, - description: adfBody // 위에서 만든 ADF 객체를 넣습니다. - } - }) - }); - - if (!response.ok) { - const errorText = await response.text(); - console.log("Payload:", JSON.stringify(adfBody, null, 2)); // 디버깅용 로그 - core.setFailed(`Jira API Error: ${response.status} ${errorText}`); - } else { - console.log(`Successfully updated Jira issue ${jiraKey} (Title & Body)`); - } \ No newline at end of file diff --git a/.github/workflows/jira-sync.yml b/.github/workflows/jira-sync.yml deleted file mode 100644 index d52c21a9..00000000 --- a/.github/workflows/jira-sync.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Create Jira Issue on GitHub Issue - -on: - issues: - types: [opened] - -permissions: - issues: write - contents: read - -jobs: - create-issue: - runs-on: ubuntu-latest - steps: - - name: Login to Jira - uses: atlassian/gajira-login@v3 - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} - - - name: Create Jira Issue - id: create - uses: atlassian/gajira-create@v3 - with: - project: "PB" # 예: PROJ (지라 프로젝트 키 대문자) - issuetype: "Task" # 예: Task, Bug, Story - summary: "[GH-#${{ github.event.issue.number }}] ${{ github.event.issue.title }}" - description: | - *GitHub Issue Link:* ${{ github.event.issue.html_url }} - - {code:bash} - ${{ github.event.issue.body }} - {code} - - - name: Comment on GitHub Issue - uses: actions/github-script@v6 - with: - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: '✅ 지라 티켓이 생성되었습니다: [${{ steps.create.outputs.issue }}](${{ secrets.JIRA_BASE_URL }}/browse/${{ steps.create.outputs.issue }})' - }) \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8646a1e3..49e2e5e7 100644 --- a/.gitignore +++ b/.gitignore @@ -57,4 +57,4 @@ front/public/firebase-config.js .idea/ .vscode/ *.iml - +/bin/ diff --git a/gradlew.bat b/gradlew.bat index 0904c2d5..11975048 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,91 +1,91 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/scripts/install-githooks.sh b/scripts/install-githooks.sh index ba693ee5..5a12caf4 100644 --- a/scripts/install-githooks.sh +++ b/scripts/install-githooks.sh @@ -3,8 +3,8 @@ set -e git config core.hooksPath .githooks -git update-index --chmod=+x .githooks/pre-commit .githooks/prepare-commit-msg .githooks/commit-msg || true -chmod +x .githooks/pre-commit .githooks/prepare-commit-msg .githooks/commit-msg scripts/secret-scan.sh || true +git update-index --chmod=+x .githooks/pre-commit .githooks/pre-push .githooks/commit-msg || true +chmod +x .githooks/pre-commit .githooks/pre-push .githooks/commit-msg scripts/secret-scan.sh || true echo "Git hooks installed (core.hooksPath=.githooks)." # ---- gitleaks auto-install (mac/linux, no package manager) ----