Skip to content

Commit 422f7bb

Browse files
committed
Merge branch 'feat/14' into feat/15
2 parents edbe8ee + 9c86277 commit 422f7bb

File tree

7 files changed

+318
-0
lines changed

7 files changed

+318
-0
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @comforest @pp8817

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
3+
### 참고 사항
4+
5+
P1: 꼭 반영해주세요 (Request changes)
6+
P2: 적극적으로 고려해주세요 (Request changes)
7+
P3: 웬만하면 반영해 주세요 (Comment)
8+
P4: 반영해도 좋고 넘어가도 좋습니다 (Approve)
9+
P5: 그냥 사소한 의견입니다 (Approve)
10+
11+
### 🔗 Related Issue
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: Add issues to project
2+
on:
3+
issues:
4+
types: [opened, reopened]
5+
6+
jobs:
7+
add-to-project:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/add-to-project@v1.0.2
11+
with:
12+
project-url: https://github.com/orgs/YAPP-Github/projects/29
13+
github-token: ${{ secrets.TOKEN_GITHUB }}

.github/workflows/link-issue.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Link Issue to PR
2+
3+
on:
4+
pull_request:
5+
types: [opened]
6+
7+
permissions:
8+
pull-requests: write
9+
issues: write
10+
11+
jobs:
12+
link-issue:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Extract Issue Number from Branch
16+
id: extract
17+
run: |
18+
BRANCH_NAME="${{ github.head_ref }}"
19+
echo "Branch name: $BRANCH_NAME"
20+
21+
# feat/{Issue ID} 패턴에서 Issue ID 추출
22+
if [[ $BRANCH_NAME =~ ^feat/([0-9]+)(\-[0-9]+)?$ ]]; then
23+
ISSUE_NUMBER="${BASH_REMATCH[1]}"
24+
echo "issue_number=$ISSUE_NUMBER" >> $GITHUB_OUTPUT
25+
echo "Found issue number: $ISSUE_NUMBER"
26+
else
27+
echo "No issue number found in branch name"
28+
echo "issue_number=" >> $GITHUB_OUTPUT
29+
fi
30+
31+
- name: Check if Issue Link Already Exists
32+
if: steps.extract.outputs.issue_number != ''
33+
id: check_link
34+
run: |
35+
PR_BODY="${{ github.event.pull_request.body }}"
36+
ISSUE_NUMBER="${{ steps.extract.outputs.issue_number }}"
37+
38+
if echo "$PR_BODY" | grep -qE "(Close[sd]?|Fix(e[sd])?|Resolve[sd]?) #$ISSUE_NUMBER"; then
39+
echo "Link already exists"
40+
echo "link_exists=true" >> $GITHUB_OUTPUT
41+
else
42+
echo "Link does not exist"
43+
echo "link_exists=false" >> $GITHUB_OUTPUT
44+
fi
45+
46+
- name: Add Issue Link to PR Description
47+
if: steps.extract.outputs.issue_number != '' && steps.check_link.outputs.link_exists == 'false'
48+
uses: actions/github-script@v7
49+
with:
50+
github-token: ${{ secrets.GITHUB_TOKEN }}
51+
script: |
52+
const issueNumber = '${{ steps.extract.outputs.issue_number }}';
53+
const currentBody = context.payload.pull_request.body || '';
54+
55+
const title = '### 🔗 Related Issue';
56+
const relatedIssueRegex = new RegExp(`${title}\\s*\\n(?:<!--[\\s\\S]*?-->\\s*\\n)*`, 'g');
57+
const closeStatement = `Closes #${issueNumber}`;
58+
59+
let newBody;
60+
if (relatedIssueRegex.test(currentBody)) {
61+
// Related Issue 섹션이 이미 있으면 그 아래에 추가
62+
newBody = currentBody.replace(
63+
relatedIssueRegex,
64+
`${title}\n\n${closeStatement}\n\n`
65+
);
66+
} else {
67+
newBody = `${currentBody}\n\n${title}\n\n${closeStatement}\n\n`;
68+
}
69+
70+
await github.rest.pulls.update({
71+
owner: context.repo.owner,
72+
repo: context.repo.repo,
73+
pull_number: context.payload.pull_request.number,
74+
body: newBody
75+
});
76+
77+
console.log(`Successfully linked issue #${issueNumber} to PR #${context.payload.pull_request.number}`);
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
name: Deploy to Sandbox
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
deploy_module:
7+
description: '배포할 모듈을 선택하세요'
8+
required: true
9+
type: choice
10+
options:
11+
- api
12+
13+
env:
14+
AWS_REGION: ap-northeast-2
15+
PHASE: sandbox
16+
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
test:
22+
name: Test & Lint
23+
runs-on: ubuntu-latest
24+
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
29+
- name: Set up JDK 17
30+
uses: actions/setup-java@v4
31+
with:
32+
java-version: '17'
33+
distribution: 'temurin'
34+
cache: 'gradle'
35+
36+
- name: Grant execute permission for gradlew
37+
run: chmod +x gradlew
38+
39+
- name: Check ktlint format
40+
run: ./gradlew ktlintCheck
41+
42+
- name: Run tests
43+
run: ./gradlew test
44+
45+
deploy:
46+
name: Deploy ${{ github.event.inputs.deploy_module }}
47+
runs-on: ubuntu-latest
48+
needs: test
49+
if: ${{ !failure() }}
50+
environment: sandbox
51+
52+
env:
53+
ECS_CLUSTER: sandbox-ecs-cluster
54+
55+
steps:
56+
- name: Set deployment config
57+
run: |
58+
case "${{ github.event.inputs.deploy_module }}" in
59+
api)
60+
echo "ECR_REPOSITORY=sandbox-app" >> $GITHUB_ENV
61+
echo "TASK_DEFINITION=sandbox-app" >> $GITHUB_ENV
62+
echo "ECS_SERVICE=sandbox-app-svc" >> $GITHUB_ENV
63+
;;
64+
*)
65+
echo "❌ Unknown deploy module: ${{ github.event.inputs.deploy_module }}"
66+
exit 1
67+
;;
68+
esac
69+
70+
- name: Checkout
71+
uses: actions/checkout@v4
72+
73+
- name: Set up Docker Buildx
74+
uses: docker/setup-buildx-action@v3
75+
76+
- name: Configure AWS credentials
77+
uses: aws-actions/configure-aws-credentials@v4
78+
with:
79+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
80+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
81+
aws-region: ${{ env.AWS_REGION }}
82+
83+
- name: Login to Amazon ECR
84+
id: login-ecr
85+
uses: aws-actions/amazon-ecr-login@v2
86+
87+
- name: Build, tag, and push image to Amazon ECR
88+
id: build-image
89+
env:
90+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
91+
IMAGE_TAG: ${{ github.sha }}
92+
uses: docker/build-push-action@v5
93+
with:
94+
context: .
95+
file: ./app/api/Dockerfile
96+
push: true
97+
build-args: |
98+
PHASE=${{ env.PHASE }}
99+
tags: |
100+
${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
101+
${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest
102+
cache-from: type=gha
103+
cache-to: type=gha,mode=max
104+
105+
- name: Set image output
106+
id: set-image
107+
run: |
108+
echo "image=${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}" >> $GITHUB_OUTPUT
109+
110+
- name: Download task definition
111+
run: |
112+
aws ecs describe-task-definition \
113+
--task-definition $TASK_DEFINITION \
114+
--query taskDefinition > task-def.json
115+
116+
- name: Update task definition
117+
run: |
118+
jq --arg IMAGE "${{ steps.set-image.outputs.image }}" \
119+
'.containerDefinitions[0].image = $IMAGE' \
120+
task-def.json > new-task-def.json
121+
122+
# 불필요한 필드 제거
123+
jq 'del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)' \
124+
new-task-def.json > final-task-def.json
125+
126+
- name: Register task definition
127+
id: register
128+
run: |
129+
TASK_DEF_ARN=$(aws ecs register-task-definition \
130+
--cli-input-json file://final-task-def.json \
131+
--query 'taskDefinition.taskDefinitionArn' \
132+
--output text)
133+
echo "task-def-arn=$TASK_DEF_ARN" >> $GITHUB_OUTPUT
134+
135+
- name: Update ECS service
136+
run: |
137+
aws ecs update-service \
138+
--cluster $ECS_CLUSTER \
139+
--service $ECS_SERVICE \
140+
--task-definition ${{ steps.register.outputs.task-def-arn }}
141+
echo "✅ API deployed successfully"
142+
143+
- name: Send Discord Notification (Success)
144+
if: success()
145+
env:
146+
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
147+
run: |
148+
if [ -n "$DISCORD_WEBHOOK_URL" ]; then
149+
THREAD_NAME="[sandbox] ${{ github.event.inputs.deploy_module }} 배포 성공"
150+
MESSAGE="- Actor: ${{ github.actor }}\n- Workflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
151+
curl -X POST "$DISCORD_WEBHOOK_URL" \
152+
-H "Content-Type: application/json" \
153+
-d "{\"content\": \"$MESSAGE\", \"thread_name\": \"$THREAD_NAME\"}"
154+
fi
155+
156+
# ❌ Plan 실패 → 스레드 이름은 동일, 메시지만 실패 표시
157+
- name: Send Discord Notification (Failure)
158+
if: failure()
159+
env:
160+
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
161+
run: |
162+
if [ -n "$DISCORD_WEBHOOK_URL" ]; then
163+
THREAD_NAME="❌ [sandbox] ${{ github.event.inputs.deploy_module }} 배포 실패"
164+
MESSAGE="- Actor: ${{ github.actor }}\n- Workflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
165+
curl -X POST "$DISCORD_WEBHOOK_URL" \
166+
-H "Content-Type: application/json" \
167+
-d "{\"content\": \"$MESSAGE\", \"thread_name\": \"$THREAD_NAME\"}"
168+
fi

app/api/Dockerfile

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Build stage
2+
FROM gradle:8.5-jdk17-alpine AS build
3+
4+
WORKDIR /app
5+
6+
# Copy Gradle wrapper and configuration files
7+
COPY gradlew gradlew.bat ./
8+
COPY gradle gradle
9+
COPY build.gradle.kts settings.gradle.kts ./
10+
11+
# Grant execute permission for gradlew
12+
RUN chmod +x gradlew
13+
RUN ./gradlew --no-daemon
14+
15+
# Copy all subproject build files
16+
COPY adapter adapter
17+
COPY app app
18+
COPY core core
19+
COPY domain domain
20+
COPY port port
21+
COPY support support
22+
23+
# Build the application
24+
RUN ./gradlew :app:api:bootJar --no-daemon
25+
26+
# Runtime stage
27+
FROM eclipse-temurin:17-jre-alpine
28+
29+
WORKDIR /app
30+
31+
# Create a non-root user for security
32+
RUN addgroup -S spring && adduser -S spring -G spring
33+
34+
# Copy the built jar from build stage
35+
COPY --from=build /app/app/api/build/libs/*.jar app.jar
36+
37+
# Change ownership to non-root user
38+
RUN chown -R spring:spring /app
39+
40+
USER spring
41+
EXPOSE 8080
42+
43+
ARG PHASE
44+
ENV JAVA_OPTS="-Dspring.profiles.active=${PHASE:-sandbox}"
45+
46+
# Run the application
47+
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

docs/a.puml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@startuml'https://plantuml.com/sequence-diagramactor Userparticipant MapServiceparticipant FEparticipant BEdatabase DBautonumberUser -> MapService: 식당 검색User -> FE: 식당 공유 링크 등록 (ex: https://naver.me/GfCsiPo3)FE -> MapService: 해당 페이지 HTML 긁어오기FE -> BE: 페이지 Response 전달BE -> DB: 페이지 정보 저장 및 투표 시스템 등록@enduml

0 commit comments

Comments
 (0)